if 不同列表内的行之间的条件,解析列表以查找匹配项,然后使用 cp

if 不同列表内的行之间的条件,解析列表以查找匹配项,然后使用 cp

请问有人可以建议我该怎么做吗?

我有两个列表(都带有 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 工具(非标准xargscp选项,其他的 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

相关内容