使用sed删除特定行的Bash脚本不起作用

时间:2012-10-20 00:40:16

标签: bash shell scripting sed

我正在尝试编写一个bash脚本来使用sed删除文件的某些行。行号以相反的顺序存储在另一个文件中。 我正在尝试执行的命令如下:

sed -e '{lineNumber}d' ./file.txt

这是我到目前为止所做的,但它不起作用

while read -r line 
do 
   sed -e "/${line}d" ./file.txt
done < ./lineNum.txt

我收到以下错误:
sed:-e expression#1,char 4:unterminated address regex

4 个答案:

答案 0 :(得分:3)

实际上你做错了就是这个

sed -e "/${line}d" ./file.txt

您看,sed具有此语法

sed -e "/REGEX/d" ./file.txt

删除包含匹配到REGEX模式的所有行。由于您有第一个/,因此sed认为您正在尝试使用正则表达式匹配,因此它会说unterminated address regex

所需的最小修正只是删除有问题的反斜杠,即

sed -e "${line}d" ./file.txt

除了:不是像OP要求的sed解决方案,而是OP更有效率的做法。

awk 'NR==FNR {arr[$0]++; next} {if (!arr[FNR]) print }' linenum.txt file.txt

答案 1 :(得分:2)

只要没有多少行要删除,并且您没有使用sed版本极为有限的系统(同时在HP-UX上sed限制为约100个命令),然后你可以使用:

sed 's/$/d/' linenum.txt | sed -f - file.txt

这使用第一个sed将行号转换为删除命令(注意你的部分麻烦是一个杂散的不必要的斜杠),然后告诉第二个sed从标准输入读取它的脚本(-f -)并将其应用于file.txt

上述内容适用于GNU sed;它在Mac OS X 10.7.5(sed)上不适用于BSD sed: -: No such file or directory。在系统上使用它之前测试它。

当然,如果您有一个bash的最新版本(适用于bash 4.2但不适用于3.2),那么您可以使用“流程替换”来解决sed

 sed -f <(sed 's/$/d/' linenum.txt) file.txt

如果这也不起作用,您可以将第一个sed命令的输出写入文件,然后使用该(临时)文件作为sed脚本的名称。所以,有很多方法可以做到这一点。但是,任何超过3个进程(两个sed和一个rm)都是奢侈的。如果你只需要做一次,这可能不是问题,但如果你必须每分钟做很多次,这可能是一个问题。

答案 2 :(得分:1)

while read -r line; do sed -i "${line} d" ./file.txt; done < ./linenum.txt

这有效(我认为你的问题是使用-e);但效率不高。最好一次传递多行来进行sed,以避免每行读取和写入一次文件。例如,您可以将linenum.txt转换为“6 d; 2 d; 1 d”之类的内容。然后将其传递给sed进行一次独家处理。

答案 3 :(得分:1)

您可以使用sed直接进行更改,而无需使用循环:

sed 's/.*/&d/' lineNum.txt | sed -i -f - file.txt