0

我正在尝试编写一个 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

4 回答 4

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

旁白:不是sed像 OP 要求的解决方案,而是更有效地做 OP 想要的。

awk 'NR==FNR {arr[$0]++; next} {if (!arr[FNR]) print }' linenum.txt file.txt
于 2012-10-20T02:05:15.450 回答
2

只要没有太多要删除的行,并且您没有在具有可悲限制版本的系统上工作sed(曾经sed在 HP-UX 上限制为大约 100 个命令),那么您可以使用:

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

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

以上适用于 GNU sed;它不适sed用于 Mac OS X 10.7.5 ( sed: -: No such file or directory) 上的 BSD。在您的系统上使用它之前对其进行测试。

当然,如果您有足够新的版本bash(适用于bash4.2 但不适用于 3.2),那么您可以使用“进程替换”来解决以下限制sed

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

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

于 2012-10-20T04:27:08.623 回答
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 进行一勺处理。

于 2012-10-20T00:54:35.197 回答
1

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

sed 's/.*/&d/' lineNum.txt | sed -i -f - file.txt
于 2012-10-20T01:02:22.413 回答