【问题标题】:trouble with 'sed' in sh scriptsh 脚本中的“sed”问题
【发布时间】:2013-12-23 04:01:14
【问题描述】:

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

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中的文本是文件名。我在这方面工作的时间比有经验的程序员所能相信的要长,而且我已经走到了尽头。上面的配置给了我所有尝试过的最明显的错误。我已经走投无路了,如果可以的话,请救救我。

第二个小问题是我的正则表达式不能替换“\”,但它适用于所有其他特殊字符。

【问题讨论】:

标签: regex unix sed pipe sh


【解决方案1】:

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

finalDocument=$(echo $updatedDocumentText | sed "s/$initialString/$desiredChange/g")

要替换反斜杠,您必须将它们加倍,例如:

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

【讨论】:

  • 感谢您的宝贵时间,实际上我在几个小时前尝试过,结果很有趣。它会正确搜索和替换,但会留下所有反斜杠!我的意思是,sed 是否有特殊字符的问题?这没有任何意义。至于第二件事,你会在我的代码中注意到,我有你推荐的所有反斜杠。
  • @user3067517:在您的问题中添加一个带反斜杠的输入字符串、您的预期输出以及您的sed 命令不起作用的方式。测试一个具体的例子对我来说更容易。
【解决方案2】:

您不需要中间文件,您可以使用 -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"

所有的引用都是重要的,并且是有目的的。 sed-e 标志并不是真正需要的,但我喜欢将它们始终放在清楚地表明它是一个表达式,而不是一个文件名参数。

关于替换特殊字符,this other answer 可能对你来说也很有趣。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    • 1970-01-01
    • 2015-08-04
    • 2015-09-07
    • 2021-01-22
    • 1970-01-01
    • 2014-08-29
    相关资源
    最近更新 更多