Bash ${.//././.} 不会更改所有出现次数

  • 本文关键字:Bash bash sh
  • 更新时间 :
  • 英文 :


>我需要替换名称中"无关紧要"的部分。这需要在 bash 脚本中完成。为此,我需要删除中间词"VAN","DEN","DE"和"DER"。

为此,我正在使用内置的替换(问题减少到 2 行):

line="STIG VAN DE WYNKELE"; 
line=${line//@(' VAN '|' DEN '|' DE '|' DER ')/' '};
echo $line;

输出:

STIG DE WYNKELE

预期产出:

STIG WYNKELE

似乎@(...)匹配了一个中间词,删除了这个中间词的所有出现,但它与其他词不匹配。

问题:我的语法是否做错了什么?如果没有,我将如何删除这些词?sed 需要文件,而我的输入是一个变量,更改后的文本也应该存储在变量中。($line应更改)

您需要

设置extglob选项。此外,删除引号,并将空格移到替代项之外。您可以进一步缩短表达式:

#!/bin/bash
line="STIG VAN DE DEN DER WYNKELE"
shopt -s extglob
line=${line//@(VAN|DE?([NR])) }
echo "$line"

通过在最后一行中双引$line,您可以查看空格是否正确删除。

bash不会回溯。首先,它在输入中找到VAN

STIG VAN DE WYNKELE
    ^^^^^|

(其中|表示扫描时的指针)。

VAN替换为 后,您有

STIG DE WYNKELE
     |

你会注意到在从 bash 开始的字符串中找不到D;你刚刚插入的空格没有被 extglob 选中。

相反,从

每个模式中删除前导空格,并删除匹配项,而不是将其替换为空格:

echo "${line//@('VAN '|'DEN '|'DE '|'DER ')}"

当然,这样做的问题是,您现在可能会删除出现在单词末尾的匹配项。没有一场比赛可以避免这种情况;相反,在一个循环中执行多个替换:

for word in VAN DEN DE DER; do
    line=${line// $word / }
done

你不需要任何CC_10模式。您可以只使用参数扩展:

${line/ * / }

例:

$ line="STIG VAN DE WYNKELE"
$ echo ${line/ * / }
STIG WYNKELE
<</div> div class="one_answers">

使用 awk :

echo $line | awk '{ if ($2 == "VAN" || $2 == "DEN" || $2 =="DE" || $2=="DER"  ) $2="";  if ($3 == "VAN" || $3== "DEN" || $3 =="DE" || $3=="DER"  ) $3="" ; print }'

相关内容

  • 没有找到相关文章

最新更新