请问有人可以建议我该怎么做吗?
我有两个列表(都带有 sha1sum 及其相对文件名),但格式不同,下面是一个示例:
列表01.txt
artist'ssomesong.mp3,3f1dfd39e88e00477483dfd578d5284f5490a0a5
hello(previous one).sh,55a5fdde4843fc2f9d9e691cb658b6389d698b22
mymovie [1989, director's cut].mov,4bdee0fc0eb7a3dbc5bbe2b65a02a1f9dc76c443
[etc...]
列表02.txt
3f1dfd39e88e00477483dfd578d5284f5490a0a5 /path/to/my new music/album.wav
f77921adf6748f65fe688a5484ed901d4g9932hh /path/to/movies/[YEAR]/mymovie [1989, director's cut].mov
55a5fdde4843fc2f9d9e691cb658b6389d698b22 /path/to/scripts,regexs/hello(previous one).sh
[etc...]
正如您所看到的,唯一好的条目是55a5fdde4843fc2f9d9e691cb658b6389d698b22
带有文件名的sha1sum hello(previous one).sh
(第 2 行list01.txt
和第 3 行list02.txt
)。
文件名和路径可以包含空格和特殊字符(例如:' " [ ] ( ) { } 等等...)。
唯一 100% 确定的是它list01.txt
始终格式化为,sha1sum
; 并且list02.txt
始终有sha1sum /
(两个/) 之前有空格。
正如这个问题的标题所示,我想使用if 条件在 bash 脚本中检查两个列表以查找匹配项(TRUE 是 ifsha1sum 和文件名相同),当它找到它们时,将使用复制每个出现的情况
cp $source $destination
source=reads the /path/to/filename from list02.txt
destination=/wherever/i/want/
谢谢!
答案1
假设:
- 存在 GNU 工具(非标准
xargs
和cp
选项,其他的 NUL 分隔符可能不起作用awk
) - 哈希值的长度始终为 40 个字符
- 始终有两个空格字符分隔哈希和文件路径
list02.txt
- 两个文件中都不存在管道
|
字符(否则使用不同的分隔符)
第一步,合并两个文件:
join -t'|' -1 2 \
<(sed -E 's/,(.{40})$/|\1/' list01.txt | sort -t'|' -k2) \
<(sed -E 's/(.{40}) /\1|/' list02.txt | sort -t'|' -k1)
- 第一个文件:替换分隔符
,
并|
在第二个字段上对文件进行排序 - 第二个文件:用第一个字段替换分隔符
(两个空格)并对
|
第一个字段进行排序 - 将文件加入哈希字段
输出:
3f1dfd39e88e00477483dfd578d5284f5490a0a5|artist'ssomesong.mp3|/path/to/my new music/album.wav
55a5fdde4843fc2f9d9e691cb658b6389d698b22|hello(previous one).sh|/path/to/scripts,regexs/hello(previous one).sh
然后用于awk
测试 field2 的文件名是否作为最后一个字段中的文件名出现。如果为 true,则打印带有 NUL 分隔符的最后一个字段,并将结果通过管道xargs
传输到以将文件复制到目标目录。
join -t'|' -1 2 \
<(sed -E 's/,(.{40})$/|\1/' list01.txt | sort -t'|' -k2) \
<(sed -E 's/(.{40}) /\1|/' list02.txt | sort -t'|' -k1) \
| awk -F '|' '
{
fname1=$2; sub(/.*\//, "", fname1) # extract filename1
fname2=$3; sub(/.*\//, "", fname2) # extract filename2
}
fname1 == fname2{ printf $3 "\0" } # compare filenames, print filepath with NUL separator
' | xargs -r0 cp -n -t /path/to/destination
复制选项:
-n
不要覆盖现有文件-t
目标目录
作为脚本:
#!/bin/bash
join -t'|' -1 2 \
<(sed -E 's/,(.{40})$/|\1/' "$1" | sort -t'|' -k2) \
<(sed -E 's/(.{40}) /\1|/' "$2" | sort -t'|' -k1) \
| awk -F '|' '
{
fname1=$2; sub(/.*\//, "", fname1) # extract filename1
fname2=$3; sub(/.*\//, "", fname2) # extract filename2
}
fname1 == fname2{ printf $3 "\0" } # compare filenames, print filepath with NUL separator
' | xargs -r0 cp -n -t "$3"
运行它作为:
./script.sh list1 list2 /path/to/destination