我正在尝试编写一个bash脚本以使用sed删除文件的某些行。行号以相反的顺序存储在另一个文件中。 我正在尝试执行的命令如下:
sed -e '{lineNumber}d' ./file.txt
这是我到目前为止所拥有的,但它不起作用
while read -r line
do
sed -e "/${line}d" ./file.txt
done < ./lineNum.txt
我收到以下错误:sed:
-e 表达式 #1,字符 4:未终止的地址正则表达式
其实你做错的是这个
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
只要没有太多的行要删除,并且您没有在具有可怜的有限版本的sed
系统上工作(曾经,HP-UX 上的sed
仅限于大约 100 个命令),那么您可以使用:
sed 's/$/d/' linenum.txt | sed -f - file.txt
这使用第一个sed
将行号转换为删除命令(请注意,您的部分麻烦是杂散的不需要的斜杠),然后告诉第二个sed
从标准输入(-f -
)读取其脚本并将其应用于file.txt
。
以上适用于GNUsed
;它不适用于Mac OS X 10.7.5(sed: -: No such file or directory
)上的BSDsed
。 在系统上使用它之前对其进行测试。
当然,如果你有一个足够新版本的bash
(适用于bash
4.2,但不适用于3.2),那么你可以使用"进程替换"来解决sed
的限制:
sed -f <(sed 's/$/d/' linenum.txt) file.txt
如果这也不起作用,您可以将第一个sed
命令的输出写入文件,然后使用该(临时)文件作为sed
脚本的名称。 所以,有很多方法可以做到这一点。 但是,任何超过 3 个进程(两次sed
和一次rm
)都是奢侈的。 如果您只需要执行一次,则可能不是问题,但是如果您必须每分钟执行多次,则可能是个问题。
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 进行一勺处理。
您可以使用sed
直接进行更改,而无需使用循环:
sed 's/.*/&d/' lineNum.txt | sed -i -f - file.txt