我正在尝试编写一个脚本来交换文件中的文本:
sed s/foo/bar/g myFile.txt > myFile.txt.updated
mv myFile.txt.updated myFile.txt
在shell中,我会唤起sed程序,它会在myFile.txt中交换文本并将更改后的文本行重定向到第二个文件。 mv然后将.updated txt文件移动到myFile.txt,覆盖它。
我需要注意“特殊字符”,但我正在使用正则表达式。
我写道:
#!/bin/sh
#First, I set up some more descriptive variables for my arguments
initialString="$1"
shift
desiredChange="$1"
shift
document="$1"
#Then, I evoke sed on my document to change all 'special characters' into
#'/special charachters'
updatedDocumentText=`sed 's:[]\[\^\$\.\*\+\-\?\\\\/]:\\\\&:g' $document`
#below, I'm checking my work
echo $updatedDocumentText
#Now, I make that 'new string' the output of a program (echo) and pipe that
#output to sed
finalDocument=echo $updatedDocumentText | sed 's/$initialString/$desiredChange/g'
#Checking my work
echo $finalDocument
#Now this string has to be the output of a program so I can use the
# redirect operator. I'm using echo as the program again.
echo $finalDocument > $document
有两个问题。最重要的是:第二个sed认为字符串$ updatedDocumentText中的文本是文件的名称。我一直在研究这个问题的时间比经验丰富的程序员能够相信的要长,而且我已经完全掌握了这一点。上面的配置给了我所尝试的所有内容中最明显的错误。我在绳子的尽头,如果可以,请救救我。
第二个小问题是,我的正则表达式不会替换'\',但它适用于所有其他特殊字符。
答案 0 :(得分:1)
我认为您忘记了特殊引号或$()
语法:
finalDocument=$(echo $updatedDocumentText | sed "s/$initialString/$desiredChange/g")
要替换反斜杠,您必须将它们加倍,例如:
sed 's/\\/\\\\/g' infile
答案 1 :(得分:0)
您不需要中间文件,您可以使用-i
标志来替换字符串:
sed -e s/foo/bar/g -i myFile.txt
不是将整个文件读入变量然后回显它,而是使用管道:修改输入并将输出传递给下一个命令。所以而不是:
updatedDocumentText=`sed 's:[]\[\^\$\.\*\+\-\?\\\\/]:\\\\&:g' $document`
finalDocument=echo $updatedDocumentText | sed 's/$initialString/$desiredChange/g'
echo $finalDocument > $document
这是“某种”等同物:
sed -e 's:[]\[\^\$\.\*\+\-\?\\\\/]:\\\\&:g' -e "s/$initialString/$desiredChange/g" -i "$document"
我说“有点”,因为你在代码中犯了其他一些错误:
sed 's/$initialString/$desiredChange/g'
中你使用了单引号,所以变量没有在那里插值,所以这个命令很可能什么都没有替换。echo $updatedDocumentText
中,某些转义的特殊字符不会被保留,可以通过双引号修复:echo "$updatedDocumentText"
最后,我认为你真正想做的是逃避$initialString
中的特殊字符,而不是文件内容。所以我认为这就是你要找的东西:
escaped=$(echo "$initialString" | sed -e 's/[].+-[$\\^*]/\\&/g')
sed -e "s/$escaped/$desiredChange/" -i "$document"
所有引用都很重要并且有用。 -e
的{{1}}标志并不是必需的,但我总是希望它们能够完全清楚它是表达式,而不是文件名参数。
关于替换特殊字符,this other answer也可能对您有用。