sed 在 bash 脚本中不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29142075/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
sed not working from within bash script
提问by asimovwasright
I have read all the similar questions on this topic, but didn't find a matching question to what I am experiencing. I apologise if this has been answered already.
我已阅读有关此主题的所有类似问题,但没有找到与我遇到的问题相匹配的问题。如果这已经得到回答,我深表歉意。
Inside a bash script I wrote, there is a very simple sed command, which does not seem to be working. There are no errors, and the command works perfectly when run from the command line.
在我编写的 bash 脚本中,有一个非常简单的 sed 命令,它似乎不起作用。没有错误,并且从命令行运行该命令时可以完美运行。
In the output from set -x I can see the sed command executing perfectly.
在 set -x 的输出中,我可以看到 sed 命令完美执行。
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
GNU bash,版本 4.3.11(1)-release (x86_64-pc-linux-gnu)
Bash script: (toned down for easier comprehension)
Bash 脚本:(为了更容易理解而淡化)
#!/bin/bash -x
# This script has the exact same sed command as used on cli
contact='"[email protected]"'
sed -i "/$contact/d" /home/tim/Desktop/file.txt
exit
Shell output:
外壳输出:
tim@ubuntu:~/Desktop$ cat file.txt
t,b,[email protected]
tim@ubuntu:~/Desktop$ ./test.sh
+ contact='"[email protected]"'
+ sed -i '/"[email protected]"/d' /home/tim/Desktop/file.txt
+ exit
tim@ubuntu:~/Desktop$ cat file.txt
t,b,[email protected]
tim@ubuntu:~/Desktop$ sed -i "/"[email protected]"/d" /home/tim/Desktop/file.txt
tim@ubuntu:~/Desktop$ cat file.txt
tim@ubuntu:~/Desktop$
I assume I am missing something very obvious, but I am done staring at it hoping for the answer to jump off the screen and slap me in the face. Please help :-)
我想我遗漏了一些非常明显的东西,但我已经盯着它看,希望答案跳出屏幕并扇我一巴掌。请帮忙 :-)
Tim
蒂姆
回答by collapsar
There are double quotes around the mail address in the $contact
script variable that are missing from the command line call:
$contact
命令行调用中缺少脚本变量中的邮件地址周围的双引号:
# case 1 - works
# only the sed pattern delimiters are enclosed in quotes and these quotes will be stripped by the shell.
sed -i "/"[email protected]"/d" ./file.txt; cat file.txt
# case 2 - fails
# escaping with \ turns dquotes #2,3 from shell-level delimiters to char literals w/o special semantics.
sed -i "/\"[email protected]\"/d" ./file.txt; cat file.txt
# case 3 - fails
# Single quotes enclose the complete sed pattern spec which comprises double quotes enclosing the mail address
sed -i '/"[email protected]"/d' ./file.txt; cat file.txt
# case 4 - works
sed -i "/[email protected]/d" ./file.txt; cat file.txt
# case 5 - works
sed -i '/[email protected]/d' ./file.txt; cat file.txt
This would explain the different behavior of the script vs. the cli call.
这将解释脚本与 cli 调用的不同行为。
The OP pointed out that he needs the double quotes in the real script. that may be so, however, if these doublequotes aren't present in the file, there will be no match.
OP 指出他在实际脚本中需要双引号。可能是这样,但是,如果文件中不存在这些双引号,则不会有匹配项。
A solution would be to preprocess the file ( if necessary, work on a copy ) with sed:
一种解决方案是使用 sed 预处理文件(如有必要,处理副本):
sed -i 's/,/","/g; s/^/"/; s/$/"/' ./file.txt
This command assumes a comma-separated list of items on each line with no item containing double quotes. It will wrap each item in double quotes so they will match against the search pattern in the original script's $contact
variable.
此命令假定每行中有一个逗号分隔的项目列表,没有包含双引号的项目。它将用双引号将每个项目括起来,以便它们与原始脚本$contact
变量中的搜索模式相匹配。
Alternative(adapted from this SO answer[that I have not been the author of])
替代方案(改编自这个 SO 答案[我不是其作者])
Another option is changing the relevant portion of the script be deriving a second variable from $contact
:
另一种选择是更改脚本的相关部分,从以下位置派生第二个变量$contact
:
contact='"[email protected]"'
c2=$(echo $contact | tr -d '"')
sed -i "/$c2/d" /home/tim/Desktop/file.txt
回答by sjsam
This is just an addition to collapsar's answer which already solved the issue.
这只是对已解决问题的 collapsar 答案的补充。
When we use sed in bash script, bash script acts as a wrapper
for sed. This has two purposes
当我们在 bash 脚本中使用 sed 时,bash 脚本充当 sed 的包装器。这有两个目的
sed command can be executed as if it is executed outside the bash.
bash script wrapper helps sed to communicate with the outside world, using environment variables.
sed 命令可以像在 bash 之外执行一样执行。
bash 脚本包装器使用环境变量帮助 sed 与外界通信。
For example, suppose that the file testfilecontains two lines
例如,假设文件testfile包含两行
[email protected]
[email protected]
Now If I would like to write a bash script which helps sed replace the lines that contain [email protected]my script sedscriptwould be like this :
现在,如果我想编写一个 bash 脚本来帮助 sed 替换包含[email protected]的行,我的脚本sedscript将是这样的:
#!/bin/bash
contact='[email protected]'
sed -i "/$contact/d"
Now I would execute the script like below
现在我将执行如下脚本
./sedscript testfile
to remove all the lines containing [email protected].
In fact you can replace $1 with the actual file name. But the important point to note, as mentioned in the previous answer, is that whenever we use a bash variable inside the sed command, always enclose the command in double quotes. Only then bash would replace the variable with corresponding string before passing it to sed.
删除所有包含[email protected]的行。
事实上,您可以将 $1 替换为实际文件名。但需要注意的重点是,如上一个答案中所述,每当我们在 sed 命令中使用 bash 变量时,请始终将命令括在双引号中。只有这样,bash 才会将变量替换为相应的字符串,然后再将其传递给 sed。