서로 다른 목록 내의 행 사이에 조건이 있는 경우 목록을 구문 분석하여 일치하는 항목을 찾은 다음 cp를 사용하세요.

서로 다른 목록 내의 행 사이에 조건이 있는 경우 목록을 구문 분석하여 일치하는 항목을 찾은 다음 cp를 사용하세요.

누구든지 나에게 무엇을 해야할지 제안해 주실 수 있나요?

두 개의 목록(둘 다 sha1sum 및 상대 파일 이름 포함)이 있지만 형식이 다릅니다. 예는 다음과 같습니다.
List01.txt

artist'ssomesong.mp3,3f1dfd39e88e00477483dfd578d5284f5490a0a5
hello(previous one).sh,55a5fdde4843fc2f9d9e691cb658b6389d698b22
mymovie [1989, director's cut].mov,4bdee0fc0eb7a3dbc5bbe2b65a02a1f9dc76c443
[etc...]

List02.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 스크립트에서 일치하는 항목이 있는지 두 목록을 확인합니다.sha1sum은 파일 이름과 동일합니다.) 그리고 이를 찾으면 다음을 사용하여 각 항목을 복사합니다.

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)
  • 첫 번째 파일: 구분 기호를 바꾸고 ,|번째 필드의 파일을 정렬합니다.
  • 두 번째 파일: 구분 기호 (공백 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그런 다음 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

관련 정보