我想编写一个简单的脚本来查找交集多个文件(所有文件中的公共行),所以在阅读了一些内容之后(关联)我尝试编写一个 bash 脚本,不幸的是我失败了。我究竟做错了什么?
RES=$(comm -12 ${1} ${2})
for FILE in ${@:3}
do
RES=$(comm -12 $FILE ${RES})
done
还有其他建议如何使用parallel
or来实现这一点吗xargs
?
答案1
函数允许递归方法
f() {
if (($# == 1))
then
cat $1;
return;
fi
comm -12 $1 <(f "${@:2}")
}
f file1 file2 file3 file4 file5...
答案2
当您取消引用RES
时:
comm $FILE ${RES}
的内容RES
替换${RES}
.但comm
需要一个文件名作为参数,因此例如 if $RES
containshello
comm
尝试打开名为hello
.
相反,您可以使用临时文件来存储过程中的公共行:
tmp=$(mktemp --tmpdir)
tmp2=$(mktemp --tmpdir)
comm -12 ${1} ${2} >$tmp
for FILE in ${@:3}
do
comm -12 $FILE $tmp >$tmp2
rm $tmp
mv $tmp2 $tmp
done
cat $tmp
rm $tmp
答案3
没有parallel
也xargs
没有comm
必要。尝试一个功能
$ intersection() { sort $@ | uniq -c | sed -n "s/^ *$# //p"; }
$ intersection file[1-3]
line2
line4
答案4
问题是comm
需要两个文件,并且$RES
是一个变量。
但我们可以欺骗并通过使用进程替换使其看起来像一个文件:
#!/bin/bash
RES=$(comm -12 ${1} ${2})
for FILE in ${@:3}
do
RES="$(comm -12 $FILE <(printf %s "${RES}"))"
done
printf %s "$RES"
您可以看到这与原来的几乎相同,但是我们使用结构<(...)
来运行命令并将其用作文件名。
所以如果我们有这三个文件:
a:line1
a:line2
a:line3
a:line4
b:line2
b:line4
b:line6
c:line2
c:line4
c:line8
我们可以对它们进行比较:
% ./allcomp a b c
line2
line4