简体   繁体   English

sed就地命令未从bash中的文件中删除

[英]sed in-place command not deleting from file in bash

I have a bash script which checks for a string pattern in file and delete entire line i same file but somehow its not deleting the line and no throwing any error .same command from command prompt deletes from file . 我有一个bash脚本,该脚本检查文件中的字符串模式并删除同一文件中的整行,但是不知何故,它不会删除该行,也不会抛出任何错误。从命令提示符处删除相同命令。

#array has patterns
for k in "${patternarr[@]}
do
   sed -i '/$k/d' file.txt
done

sed version is >4 sed版本> 4

when this loop completes i want all lines matching string pattern in array to be deleted from file.txt 当此循环完成时,我希望将与数组中的字符串模式匹配的所有行从file.txt中删除

when i run sed -i '/pataern/d file.txt from command prompt then it works fine but not inside bash Thanks in advance 当我从命令提示符下运行sed -i '/pataern/d file.txt ,它工作正常,但在bash中却无法运行

Here: 这里:

sed -i '/$k/d' file.txt

The sed script is singly-quoted , which prevents shell variable expansion. sed脚本用单引号引起来 ,以防止shell变量扩展。 It will (probably) work with 它将(可能)与

sed -i "/$k/d" file.txt

I say "probably" because what it will do depends on the contents of $k , which is just substituted into the sed code and interpreted as such. 我说“可能”是因为它的作用取决于$k的内容,该内容仅被替换为sed代码并如此解释。 If $k contains slashes, it will break. 如果$k包含斜杠,它将破折号。 If it comes from an untrustworthy source, you open yourself up to code injection (particularly with GNU sed, which can be made to execute shell commands). 如果它来自不可靠的来源,则可以进行代码注入(特别是使用GNU sed,可以执行shell命令)。

Consider k=^/ s/^/rm -Rf \\//e; # 考虑k=^/ s/^/rm -Rf \\//e; # k=^/ s/^/rm -Rf \\//e; # . k=^/ s/^/rm -Rf \\//e; #

It is generally a bad idea to substitute shell variables into sed code (or any other code). 将shell变量替换为sed代码(或任何其他代码)通常是一个坏主意。 A better way would be with GNU awk: 更好的方法是使用GNU awk:

awk -i inplace -v pattern="$k" '!($0 ~ pattern)' file.txt

Or to just use grep -v and a temporary file. 或者仅使用grep -v和一个临时文件。

first of all, you got an unclosed double quote around ${patternarr[@]} in your for statement. 首先,您的for语句中有一个围绕${patternarr[@]}双引号。

Then your problem is that you use single quotes in the argument, making your shell not evaluate the $k within the quotes: 然后您的问题是,您在参数中使用了单引号,使您的shell无法评估引号内的$k

% declare -a patternarr=(foo bar fu foobar)
% for k in ${patternarr[@]}; do echo sed -i '/$k/d' file.txt; done
sed -i /$k/d file.txt
sed -i /$k/d file.txt
sed -i /$k/d file.txt
sed -i /$k/d file.txt

if you replace them with double quotes, here it goes: 如果将它们替换为双引号,则结果如下:

% for k in ${patternarr[@]}; do echo sed -i "/$k/d" file.txt; done
sed -i /foo/d file.txt
sed -i /bar/d file.txt
sed -i /fu/d file.txt
sed -i /foobar/d file.txt

Any time you write a loop in shell just to manipulate text you have the wrong approach. 任何时候在shell中编写循环来操纵文本时,您都会使用错误的方法。 This is probably closer to what you really should be doing (no surrounding loop required): 这可能更接近您真正应该做的事情(不需要环绕循环):

awk -v ks="${patternarr[@]}" 'BEGIN{gsub(/ /,")|(",ks); ks="("ks")} $0 !~ ks' file.txt

but there may be even better approaches still (eg only checking 1 field instead of the whole line, or using word boundaries, or string comparison or....) if you show us some sample input and expected output. 但是,如果您向我们展示一些示例输入和预期输出,则可能还有更好的方法(例如,仅检查1个字段而不是整行,或使用单词边界或字符串比较或...。)

You need to use double quotes to interpolate shell variables inside the command, like: 您需要使用双引号在命令中插值shell变量,例如:

for k in ${patternarr[@]}; do
    sed -i "/$k/d" file.txt
done

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM