实施例1

实施例1

我有一个示例文本文件,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 -Fawk

如果您仍然想使用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 指定。)

相关内容