我正在尝试使用 sed 删除以特定方式格式化的文本文件中的列表中的特定项目。我简单举例说明一下;我有...
ITEMS="$ITEM $ITEM1 $ITEM2 $ITEM3"
我想从列表中删除 $ITEM,这样这将变成...
ITEMS="$ITEM1 $ITEM2 $ITEM3"
列表甚至还可以只包含 $ITEM 而没有编号的 $ITEM,例如 ...
ITEMS="$ITEM"
这将变成
ITEMS=""
当然,一旦 $ITEM 被删除。
执行此查找/删除时,不知道列表中存在多少个 $ITEM。所述文本文件除此行之外还包含其他文本,但ITEMS=对于文本文件行的开头是唯一的,即这是唯一以ITEMS=开头的行。所以基本上,我想找到以 ITEMS= 开头的行并从中删除 $ITEM 元素。如何使用 sed 最好地完成此任务?
$ITEM
前后的空格真的很烦人。 :)
尝试这条线:
sed -r 's/"\$ITEM /"/; s/\$ITEM //g; s/ ?\$ITEM"/"/' file
用一些例子进行测试:
kent$ echo 'ITEMS="$ITEM"'|sed -r 's/"\$ITEM /"/; s/\$ITEM //g; s/ ?\$ITEM"/"/'
ITEMS=""
7pLaptop 20:57:44 /home/kent/myCodes/vim/last256
kent$echo 'ITEMS="$ITEM $ITEM1 $ITEM2 $ITEM $ITEM3 $ITEM"'|sed -r 's/"\$ITEM /"/; s/\$ITEM //g; s/ ?\$ITEM"/"/'
ITEMS="$ITEM1 $ITEM2 $ITEM3"
编辑
对于OP的评论,添加解释。
's/"\$ITEM /"/; #step1 check if the first element is $ITEM, do sub
s/\$ITEM //g; #step2 handle the middle elements
s/ ?\$ITEM"/"/' #step3 handle the last element case. also this handles single ("$ITEM") case.
我使用了 3 个步骤,因为 OP 希望处理后具有相同的格式(单个空格分隔值)。也许有更简单/更好的解决方案,我只是想到了这种方式,分三步进行替换/格式化。 :(
我们可以在这里使用正则表达式捕获组的强大功能。这是一个神奇的例子:
$ echo 'ITEM1 ITEM2 ITEM3 ITEM4' | sed -r 's/(.*)( ITEM2|ITEM2( |$))(.*)/\1\4/g'
ITEM1 ITEM3 ITEM4
$ echo 'ITEM1 ITEM2 ITEM3 ITEM4' | sed -r 's/(.*)( ITEM4|ITEM4( |$))(.*)/\1\4/g'
ITEM1 ITEM2 ITEM3
$ echo 'ITEM1 ITEM2 ITEM3 ITEM4' | sed -r 's/(.*)( ITEM4|ITEM4( |$))(.*)/\1\4/g'
ITEM1 ITEM2 ITEM3
$ echo 'ITEM1' | sed -r 's/(.*)( ITEM1|ITEM1( |$))(.*)/\1\4/g'
解释。正则表达式中括号中的部分表示“捕获组”。它们在这里,按特定顺序排列:
.*
- 我们要删除的项目之前的所有内容。 $ITEM_TO_DELETE|ITEM_TO_DELETE( |$)
- 我们要删除的部分。 |$
- 我们要删除的项目末尾的空格或 EOL(请注意,该组位于第 2 组中,但仍然是一个单独的组。
.*
现在是最棘手的部分。第 2 组与以下其中一项比赛:
我们要删除的项目,前面加一个空格
\1\4
。
sed 表达式的一般表示如下:"s/(.*)( $ITEM|$ITEM( |$))(.*)/\1\4/g"
其中
$ITEM
是包含我们要删除的项目的变量。
echo 'a list of words' | sed 's/\<list\>//g'