我有两个文件 A 和 B。两个文件中的每一行都被视为一个项目。每个项目的格式都是固定的,由键和描述组成,并用空格分隔。如下例所示。
UASCH-XCF02-SP062 /users/documents/ark
第一部分UASCH-XCF02-SP062
是重点,最后一部分/users/documents/ark
是说明。文件 A 和 B 分别有 1000 和 100000 个项目。同一文件中的每个键都是唯一的,但文件 A 中的项的键也出现在文件 B 中,但描述不同。如下一个简单的例子所示。
文件A
UASCH-XCF02-SP062 /users/documents/ark1
UASCH-XXF02-SP063 /users/documents/ark2
文件B
UASCH-XCF02-SP062 /users/documents/ark3
UASCH-XXF02-SP063 /users/documents/ark4
UASCH-XXF03-SP064 /users/documents/ark5
我想将文件B中相同key对应的描述替换为文件A中key对应的描述。示例中的结果如下所示。
文件B
UASCH-XCF02-SP062 /users/documents/ark1
UASCH-XXF02-SP063 /users/documents/ark2
UASCH-XXF03-SP064 /users/documents/ark5
如何实现这个目标?
答案1
这可以使用 AWK 来完成:
$ awk 'NR==FNR{a[$1]=$2;next} $1 in a {$2=a[$1]} 1' A.txt B.txt
UASCH-XCF02-SP062 /users/documents/ark1
UASCH-XXF02-SP063 /users/documents/ark2
UASCH-XXF03-SP064 /users/documents/ark5
编辑:由于 Ed 的评论,简化了 AWK 表达式的后半部分。
要编辑文件 B,请将 AWK 输出重定向到临时文件,然后用它替换文件 B,如下所示:
awk 'NR==FNR{a[$1]=$2;next} $1 in a {$2=a[$1]} 1' A.txt B.txt >B.txt.tmp
mv B.txt.tmp B.tmp
怎么运行的。我们首先将第一个文件(A)的所有键值对保存到一个关联数组中,使用NR==FNR
习惯用法来区分第一个文件和第二个文件。然后,当我们遍历第二个文件 (B) 时,我们将检查当前密钥是否存在于第一个文件中,如果存在,我们将当前值替换为第一个文件中找到的值。
答案2
纯bash
...如果bash
是您的 shell,那么您只需使用 shell 内置函数即可完成此操作,不需要外部实用程序/命令...但是,在某些情况下,它可能比专用文本处理工具慢一点,但是尽管如此,了解一下还是会有帮助的。
array
像这样声明一个关联数组:
declare -A array
A
然后使用空格 ie作为内部字段分隔符将文件读入其中,如下所示:
while IFS=' ' read -r k v
do
array[$k]="$v"
done < A
然后读取文件B
行,比较键,替换值并打印最终结果,如下所示:
while IFS=' ' read -r k v
do
if [[ "${!array[*]}" =~ "$k" ]]
then
printf '%s %s\n' "$k" "${array[$k]}"
else
printf '%s %s\n' "$k" "$v"
fi
done < B
这将输出:
UASCH-XCF02-SP062 /users/documents/ark1
UASCH-XXF02-SP063 /users/documents/ark2
UASCH-XXF03-SP064 /users/documents/ark5
注意: 作为bash 数组是一维的,上述方法将适用于您的用例(IE一钥匙和一价值) 和类似的,但不适用于具有多个值的键,当每个额外值需要解析为单独的标记时。
答案3
排序是固定的,并且 'uniq' 可以只考虑前 N 个字符,所以......
cat AB | 排序 | uniq -w 17 > /tmp/foo ; cp /tmp/foo B
是的 - 它按预期工作
$ cat A B | sort | uniq -w 17
UASCH-XCF02-SP062 /users/documents/ark1
UASCH-XXF02-SP063 /users/documents/ark2
UASCH-XXF03-SP064 /users/documents/ark5