好的,我的 linux 框中的文本文件中有两个相关列表:
/tmp/oldList
/tmp/newList
我需要比较这些列表以查看添加了哪些行以及删除了哪些行。然后我需要遍历这些行并根据它们是添加还是删除对它们执行操作。
我如何在 bash 中做到这一点?
使用comm(1)
命令比较两个文件。它们都需要排序,如果它们很大,您可以事先进行排序,或者您可以使用 bash process substitution内联进行排序。
comm
可以采用标志的组合-1
,-2
并-3
指示要从哪个文件中抑制行(文件 1 独有,文件 2 独有或两者共有)。
要仅在旧文件中获取行:
comm -23 <(sort /tmp/oldList) <(sort /tmp/newList)
要仅在新文件中获取行:
comm -13 <(sort /tmp/oldList) <(sort /tmp/newList)
您可以将其输入while read
循环以处理每一行:
while read old ; do
...do stuff with $old
done < <(comm -23 <(sort /tmp/oldList) <(sort /tmp/newList))
对于新线路也是如此。
如果您的脚本需要可读性,请考虑使用 Ruby。
要仅在旧文件中获取行:
ruby -e "puts File.readlines('/tmp/oldList') - File.readlines('/tmp/newList')"
要仅在新文件中获取行:
ruby -e "puts File.readlines('/tmp/newList') - File.readlines('/tmp/oldList')"
您可以将其输入 while read 循环以处理每一行:
while read old ; do
...do stuff with $old
done < ruby -e "puts File.readlines('/tmp/oldList') - File.readlines('/tmp/newList')"
这是旧的,但为了完整起见,我们应该说,如果你有一个非常大的集合,最快的解决方案是使用 diff 生成一个脚本然后获取它,如下所示:
#!/bin/bash
line_added() {
# code to be run for all lines added
# $* is the line
}
line_removed() {
# code to be run for all lines removed
# $* is the line
}
line_same() {
# code to be run for all lines at are the same
# $* is the line
}
cat /tmp/oldList | sort >/tmp/oldList.sorted
cat /tmp/newList | sort >/tmp/newList.sorted
diff >/tmp/diff_script.sh \
--new-line-format="line_added %L" \
--old-line-format="line_removed %L" \
--unchanged-line-format="line_same %L" \
/tmp/oldList.sorted /tmp/newList.sorted
source /tmp/diff_script.sh
更改的行将显示为已删除和添加。如果你不喜欢这样,你可以使用--changed-group-format。检查差异手册页。
我通常使用:
diff /tmp/oldList /tmp/newList | grep -v "Common subdirectories"
该grep -v
选项反转匹配:
-v, --invert-match 选定的行是那些不匹配任何指定模式的行。
因此,在这种情况下,它会获取diff
结果并忽略那些常见的结果。
你有没有尝试过diff
$ diff /tmp/oldList /tmp/newList
$ man diff