Regex 与';sed';用sh脚本

Regex 与';sed';用sh脚本,regex,unix,sed,pipe,sh,Regex,Unix,Sed,Pipe,Sh,我正在尝试编写一个脚本来交换文件中的文本: 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,

我正在尝试编写一个脚本来交换文件中的文本:

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中的文本是文件名。我从事这项工作的时间比有经验的程序员所能相信的要长,对此我已经穷途末路了。上面的配置给了我所有尝试中最明显的错误。我已经穷途末路了,如果可以的话,请救救我


第二个小问题是,我的正则表达式没有替换“\”,但它可以处理所有其他特殊字符。

我想你忘记了特殊引号,或者
$()
语法:

finalDocument=$(echo $updatedDocumentText | sed "s/$initialString/$desiredChange/g")
要替换反斜杠,必须将其加倍,如:

sed 's/\\/\\\\/g' infile

我想您忘记了特殊引号,或者
$()
语法:

finalDocument=$(echo $updatedDocumentText | sed "s/$initialString/$desiredChange/g")
要替换反斜杠,必须将其加倍,如:

sed 's/\\/\\\\/g' infile

您不需要中间文件,您可以使用
-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的/$initialString/$desiredChange/g'
    中,您使用了单引号,因此变量没有插入其中,因此该命令很可能不替换任何内容
  • echo$updatedDocumentText
    中,一些转义的特殊字符将不会被保留,这可以通过双引号来修复:
    echo“$updatedDocumentText”
最后,我认为您真正想要做的是转义
$initialString
中的特殊字符,而不是转义文件内容中的特殊字符。所以我想这就是你想要的:

escaped=$(echo "$initialString" | sed -e 's/[].+-[$\\^*]/\\&/g')
sed -e "s/$escaped/$desiredChange/" -i "$document"
所有的引用都是有意义的,并且是有目的的。
sed
-e
标志实际上并不是必需的,但我总是想把它们放在一起,以清楚地表明它是一个表达式,而不是一个文件名参数


关于替换特殊字符,您可能也会感兴趣。

您不需要中间文件,您可以使用
-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的/$initialString/$desiredChange/g'
    中,您使用了单引号,因此变量没有插入其中,因此该命令很可能不替换任何内容
  • echo$updatedDocumentText
    中,一些转义的特殊字符将不会被保留,这可以通过双引号来修复:
    echo“$updatedDocumentText”
最后,我认为您真正想要做的是转义
$initialString
中的特殊字符,而不是转义文件内容中的特殊字符。所以我想这就是你想要的:

escaped=$(echo "$initialString" | sed -e 's/[].+-[$\\^*]/\\&/g')
sed -e "s/$escaped/$desiredChange/" -i "$document"
所有的引用都是有意义的,并且是有目的的。
sed
-e
标志实际上并不是必需的,但我总是想把它们放在一起,以清楚地表明它是一个表达式,而不是一个文件名参数


关于替换特殊角色,您可能也会感兴趣。

谢谢您的时间,我在几个小时前就尝试过了,结果非常有趣。它会正确地搜索和替换,但会留下所有的反斜杠!我是说,sed对特殊角色有问题吗?这毫无意义。至于第二件事,你会注意到在我的代码中,我有你推荐的所有反斜杠。@user3067517:在你的问题中添加一个带有反斜杠的输入字符串,你的预期输出以及你的
sed
命令不起作用的方式。对我来说,测试一个具体的例子比较容易。谢谢你的时间,我在几个小时前就试过了,结果很搞笑。它会正确地搜索和替换,但会留下所有的反斜杠!我是说,sed对特殊角色有问题吗?这毫无意义。至于第二件事,你会注意到在我的代码中,我有你推荐的所有反斜杠。@user3067517:在你的问题中添加一个带有反斜杠的输入字符串,你的预期输出以及你的
sed
命令不起作用的方式。对我来说,测试一个具体的例子比较容易