我有一个包含大约几千行的列表,每行包含 4 或 5 个字段。我还有第二个列表,包含多行,只有 1 个字段。两个列表都将存储在变量中。
第一个列表:
item_1 something something value something
item_2 something something value
item_3 something something value something
item_4 something something value something
...
item_2155 something something value
item_2156 something something value something
第二个清单:
item_3
item_2155
期望的最终结果:
item_1 something something value something
item_2 something something value
item_3 something something new_value something
item_4 something something value something
...
item_2155 something something new_value
item_2156 something something value something
我尝试在 while 循环中使用 sed 。它有点有效,但此方法每次循环时都会将列表附加到自身。我也觉得 awk 可能是更好的解决方案。
#!/bin/bash
MYHUGELIST=$(command)
MYSHORTLIST=$(command)
while read -r line ; do
sed "/^$line /s/1of3-possible-matches/newvalue/;/^$line /s/2of3-possible-matches/newvalue/;/^$line /s/3of3-possible-matches/newvalue/" <<< "$MYHUGELIST"
done <<< "$MYSHORTLIST"
答案1
awk
您会考虑使用而不使用的解决方案sed
吗?如果是,
#!/bin/bash
read -r -d '' shortlistOneString < shortlist.txt
awk -v oldv=value -v newv=new_value -v s="$shortlistOneString" \
'BEGIN {n=split(s,a,"\n")} { \
found=0; \
for (i=1; ! found && i<=n; ++i) { \
if (a[i] == $1) { \
for (j=2; j<= NF; ++j) { \
if ($j == oldv) { \
$j = newv; found=1; break }}}}; \
print}' longlist.txt
笔记
- 我们将整个
shortlist.txt
、换行符和所有内容读入 shell 变量shortlistOneString
。 - 在
BEGIN
块中,我们将 的值拆分"$shortlistOneString"
为一个称为 的数组a
;这个数组有n
元素,我们可以访问我th 元素与a[i]
.该块仅awk
在输入正确之前执行一次。 - 就其本身而言,
awk
将每一行解析为一个特殊的保留数组;对于任何输入行,该数组都有NF
元素,我们可以访问j第一个元素带有$j
;甚至可以覆盖这些元素。 - 对于每一行,
awk
将执行第二个块中的语句(其第一个语句是found=0
,最后一个语句是print
)。 - 如果j第一个字段等于
oldv
,我们用 覆盖该字段newv
,然后停止查找。因为awk
没有break
Bash(例如)那样的多级,所以我们使用一个名为 的辅助变量来凑合found
,我们0
为每行重置该变量。 - 无论我们是否覆盖字段,我们都会
print
一行一行。 - 该解决方案比您所要求的更通用。您可以通过仅检查每行的来收紧它最后一个字段
$(NF)
和倒数第二个字段$(NF-1)
;您甚至可以分别将字段位置硬编码为$5
和$4
。
答案2
您可以使用 sed 发出 awk 脚本
cmd1 | awk "$(cmd2 | sed -e 's:.*:/^& /{\$4=\"new_value\"}:')1"
在哪里
cmd1
产生$MYHUGELIST
cmd2
产生$MYSHORTLIST
- 中的每一行都
$MYSHORTLIST
变成/^item_N /{$4="new_value"}
- awk 脚本中的结尾
1
会导致打印当前行 $
并且"
根据需要对字符进行转义
或者,仅限 sed,
cmd1 | sed -e "$(cmd2 | sed -e 's:.*:/^& /s/[^ ][^ ]*/new_value/4:')"
其中命令4
中的标志s
选择第四个字段。
答案3
您所需要的只是对 awk 的一次简单调用,无需循环、管道或其他命令。
如果您的数据位于文件中:
$ awk 'NR==FNR{a[$1]; next} $1 in a{$4="new_value"} 1' secondFile firstFile
item_1 something something value something
item_2 something something value
item_3 something something new_value something
item_4 something something value something
...
item_2155 something something new_value
item_2156 something something value something
或者如果您的数据位于变量中:
$ awk -v sec="$second" '
BEGIN{split(sec,tmp); for (i in tmp) a[tmp[i]]}
$1 in a{$4="new_value"} 1
' <<<"$first"
item_1 something something value something
item_2 something something value
item_3 something something new_value something
item_4 something something value something
...
item_2155 something something new_value
item_2156 something something value something