迭代时无法从文件替换String

时间:2018-09-19 03:58:15

标签: bash shell replace

final.txt如下:

build/create_changes.sh
build/create_changes.sh-meta.xml
src/aura/camping/camping.design
src/aura/camping/camping.design-meta.xml

我只想将其行中包含/aura/的文件替换为src/aura/camping

if [ -e final.txt ]
then
        ARRAY=()
        while read CFILE
            do
                    echo Analyzing file `basename $CFILE`
                    case "$CFILE"
                    in
                        *.design) TYPENAME="AuraDefinitionBundle";;
                        *) TYPENAME="UNKNOWN";;
                    esac

                    if [ "$TYPENAME" == "AuraDefinitionBundle" ]
                        then
                                if [ $(contains "${ARRAY[@]}" $(basename -- "$(dirname -- "$CFILE")")) != "y" ]
                                then
                                    echo baseFile from new method cFile $CFILE
                                    CFILENAME="$CFILE"

                                    replace="src/aura/"$(basename -- "$(dirname -- "$CFILE")")
                                    echo checkChanges "${CFILENAME/$CFILENAME/"$replace"}"
                                    CFILE="${CFILENAME/$CFILENAME/"$replace"}"
                                    echo baseFile from after change method cFile $CFILE
                                else
                                    continue
                                fi
                        fi
            done < final.txt
else
echo Change file not found!

这有效,所以我现在可以在窗口中看到它:

 [exec] baseFile from new method cFile src/aura/camping/camping.design
 [exec] checkChanges src/aura/camping
 [exec] baseFile from after change method cFile src/aura/camping

但是文件final.txt不变:

build/create_changes.sh
build/create_changes.sh-meta.xml
src/aura/camping/camping.design
src/aura/camping/camping.design-meta.xml

我在那里CFILE="${CFILENAME/$CFILENAME/"$replace"}"

替换了它

也尝试过:

if [ $(contains "${ARRAY[@]}" $(basename -- "$(dirname -- "$CFILE")")) != "y" ]
then
    CFILENAME="$CFILE"
    ARRAY+=($(basename -- "$(dirname -- "$CFILE")"))
    replace="src/aura/"$(basename -- "$(dirname -- "$CFILE")")
    #CFILE="${CFILENAME/$CFILENAME/"$replace"}"
    sed -i 's/$CFILENAME/$replace/' final.txt
else
    continue
fi

我在这里还想念其他东西吗?

1 个答案:

答案 0 :(得分:2)

大多数情况下,您的尝试都很有用,但是两次尝试中涉及更改文件内容的部分都不正确。

Problem 1

您对以下尝试未替换文件内容感到惊讶。不会。

CFILE="${CFILENAME/$CFILENAME/"$replace"}"

因为上面是一个bash内部构造,用于替换字符串。它只是替换存储在变量CFILENAME中的字符串内容,并将结果放入CFILE中。完全不进行文件修改。

从您的输入判断,您的CFILENAME输入将是src/aura/camping/camping.design,而replace变量将是src/aura/camping。进行上述操作会将字符串src/aura/camping放入变量CFILE,而 not 放入变量CFILE指向的文件。

Problem 2

您似乎已经确定sed将解决您的问题,这是正确的,但是您似乎错过了一些技巧。

  1. 您在sed搜索和替换零件中定义了变量,但是引号引起了问题。 bash shell中的变量在用单引号引起来时不会扩展,而只能用双引号引起来。
  2. 下一个问题是sed中使用的分隔符字符串,默认情况下为/。但是请记住,源字符串和替换字符串都包含/,因此sed不会理解什么是原始文本和替换文本。您需要定义一个非/的分隔符,以及不属于您字符串的任何元字符。我建议您使用|

    sed "s|$CFILENAME|$replace|" final.txt
    
  3. 现在最大的问题是您的-i命令中的sed标志,这意味着您可以随时编辑文件。请记住,您正在使用while read逐行构造循环读取文件,现在在解析每一行之后编辑此文件。您在这里用错误的方式弄乱了shell重定向。理想的方法是将逐行编辑重定向到一个临时文件,并在循环完成后将其移动到原始文件。

    sed "s|$CFILENAME|$replace|" final.txt >> temp_final.txt
    

使用>>附加到文件的上述操作。循环结束后,使用mv

恢复为原始文件
mv -- temp_final.txt final.txt