我有一个示例文本文件,result.txt
只是为了演示:
{HEX}.A.Bs
{HEX}.A.Bss
{HEX}.A.Bsss
{HEX}.A.Bssss
但在实际应用中, 的内容result.txt
可以逐行包含任何字符,例如:
/usr/local/abc.txt
/var/tmp/
png
OIPOP()_+(_)&*#)@IOJDNU*@Utest
我想通过 bash 脚本中的参数删除一行字符串。因此,在我的 bash 脚本中test.sh
,我有以下代码:
!/bin/sh
#test.sh
result=result.txt
del="$1"
sed -i "/$del/d" $result
cat result.txt
实施例1
因此,要删除"{HEX}.A.Bs"
,我使用参数运行以下脚本:
./test.sh "{HEX}.A.Bs"
这应该删除一个名为"{HEX}.A.Bs"
inside 的字符串result.txt
但里面的所有内容 result.txt
被删除。预期输出应该是:
{HEX}.A.Bss
{HEX}.A.Bsss
{HEX}.A.Bssss
实施例2
如果我想删除"{HEX}.A.Bss"
:
./test.sh "{HEX}.A.Bss"
上面的例子只留下一个字符串 "{HEX}.A.Bs"
里面 result.txt
。它应该只删除字符串"{HEX}.A.Bss"
。所以,这个的预期输出示例2应该产生这样的结果:
{HEX}.A.Bs
{HEX}.A.Bsss
{HEX}.A.Bssss
我可以知道这里的代码有什么问题吗?
答案1
如果要删除与字符串匹配的行,请使用能够理解文字字符串的工具,例如使用 GNU awk 进行就地编辑(就像 GNU sed 一样):
del="$1" awk -i inplace '($0"") != ENVIRON["del"]' "$result"
答案2
使用perl
(-i
一些现代实现支持的非标准选项sed
实际上是从 借用的perl
):
LINE_TO_REMOVE='{HEX}.A.Bs' perl -i -nle '
print if $_ ne $ENV{LINE_TO_REMOVE}' -- "$file"
要使用sed
(这里假设 GNUsed
或兼容),您首先需要对字符串中的正则表达式运算符进行转义以进行匹配(包括.
示例中使用的未转义的字符将匹配任何单个字符)并将其分别用 和 锚定在开头和^
结尾$
。
string='{HEX}.A.Bs'
regexp='^'$(printf '%s\n' "$string" | sed 's:[][\\/.^$*]:\\&:g')'$'
sed -i -e "/$regexp/d" -- "$file"
(它还假设$string
文件包含有效文本)。
答案3
您的代码的问题在于您成功匹配了子{HEX}.A.Bss
字符串每一个线。
假设你的字符串不包含需要转义的字符,你可以改用
sed "/^$string\$/d" filename
即,将图案锚定在线的开头和结尾。
自从有了图案做包含需要转义的字符( ,匹配单个字符),使用, 或进行字符串比较.
会更安全。grep -F
awk
如果您仍然想使用sed
,请确保字符串中的所有点都匹配为点,而不是其他任何内容:
pattern=$( printf '%s\n' "$string" | sed 's/[.]/[.]/g' )
sed "/^$pattern\$/d" filename
要删除与字符串完全匹配的行,请使用
grep -v -xF -e "$string" filename >newfile && mv newfile filename
这里使用的选项grep
是
-v
:否定测试的意义,即所有行不是匹配的模式被提取。-x
:要求整行符合给定的模式。-F
:将模式视为字符串而不是正则表达式。-e
:“下一个参数是模式”。如果值$string
以破折号开头,则需要这样做。
要保留尽可能多的原始文件的元数据(例如所有权、权限等),请复制它,将操作grep
应用于副本,并将结果重定向到原始文件:
cp filename filename.tmp &&
grep -v -xF -e "$string" filename.tmp >filename
rm -f filename.tmp
答案4
我相信 \b
这是为了单词边界,并且以防万一该行包含"{HEX}.A.Bs anotherword"
或"{HEX}.A.Bs filename"
(即字符串包含空格和“filename”作为文件名),它也会删除它。
因此,如果您只想删除特定的“{HEX}.A.Bs”,最好使用:
$ sed '|^'"$del"'$|d' $result
"$del"
包含您传递的字符串以及'
它们之间的单引号,告诉您完全按照原样匹配它,而不是作为模式。
珀尔:
perl -pe "s|^\Q$del\E$||g;" $result | sed '/^$/d'
\Q
=> 引用(禁用)模式元字符直到\E
如果您想要就地编辑(直接更改/编辑文件),您可以使用:
$ perl -pe "s|^\Q$del\E$||g;" $result | sed '/^$/d' > tmpfile && mv tmpfile $result
如果你想使用 awk :
$ awk -v d=$del '$0 != d' $result > tmp && mv tmp $result
如果你想使用 grep:
$grep -vxF "$del" $result > tmp && mv tmp $result
-F,--fixed-strings, --fixed-regexp 将 PATTERN 解释为固定字符串列表
-v,--invert-match 反转匹配的意义,以选择不匹配的行。 (-v 由 POSIX 指定。)
-X,--line-regexp 仅选择那些与整行完全匹配的匹配项。 (-x 由 POSIX 指定。)