どうか、どうすればよいか親切に教えていただけませんか?
リストが 2 つあります (どちらも 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
としてフォーマットされ、常に(/ の前に 2 つのスペース) が含まれることです。,sha1sum
list02.txt
sha1sum /
この質問のタイトルにあるように、私はif条件bashスクリプトでは、両方のリストをチェックして一致するものを見つけます(TRUEはsha1sumとファイル名は同じです) を見つけ、見つかったら、すべての出現箇所をコピーします。
cp $source $destination
source=reads the /path/to/filename from list02.txt
destination=/wherever/i/want/
ありがとう!
答え1
前提:
- GNU ツールが存在します (非標準
xargs
およびcp
オプション、他の 's の NUL 区切りが機能しない可能性がありますawk
) - ハッシュの長さは常に40文字です
- ハッシュとファイルパスを区切るスペースは常に2つあります。
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)
- 最初のファイル:区切り文字
,
を置き換え|
、2番目のフィールドでファイルをソートします。 - 2番目のファイル: 区切り文字
(2つのスペース)を置き換え
|
、最初のフィールドで並べ替えます。 - ハッシュフィールドでファイルを結合する
出力:
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
フィールド 2 のファイル名が最後のフィールドのファイル名として存在するかどうかをテストするために使用します。 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