se a condição entre linhas dentro de listas diferentes, analise as listas em busca de correspondências e use cp

se a condição entre linhas dentro de listas diferentes, analise as listas em busca de correspondências e use cp

Por favor, alguém poderia me sugerir como fazer?

Eu tenho duas listas (ambas com sha1sums e seus nomes de arquivos relativos), mas formatadas de forma diferente, aqui está um exemplo:
lista01.txt

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

lista02.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...]


Como você pode ver, a única entrada boa é para sha1sum 55a5fdde4843fc2f9d9e691cb658b6389d698b22com nome de arquivo hello(previous one).sh(2ª linha list01.txte 3ª linha list02.txt).
Nomes de arquivos e caminhos podem conter espaços em branco e caracteres especiais (ex.: ' " [ ] ( ) { } e assim por diante...).
A única coisa para ter 100% de certeza é que list01.txté sempre formatado como ,sha1sum; e list02.txtsempre terá sha1sum /(dois espaços antes de /).

Como no título desta pergunta, gostaria de usar umse-condiçãoem um script bash que verifica ambas as listas para encontrar correspondências (TRUE é setanto sha1sum quanto filename são iguais) e quando os encontrar, copiará todas as ocorrências usando

cp $source $destination
source=reads the /path/to/filename from list02.txt
destination=/wherever/i/want/


Obrigado!

Responder1

Premissas:

  • Ferramentas GNU estão presentes (não padrão xargse cpopções, possivelmente separador NUL não funcional em outros awk)
  • O comprimento do hash é sempre de 40 caracteres
  • Sempre há dois caracteres de espaço separando o hash e o caminho do arquivo emlist02.txt
  • Nenhum |caractere de barra vertical está presente em ambos os arquivos (caso contrário, use um separador diferente)

Primeiro passo, mescle os dois arquivos:

join -t'|' -1 2 \
    <(sed -E 's/,(.{40})$/|\1/' list01.txt | sort -t'|' -k2) \
    <(sed -E 's/(.{40})  /\1|/' list02.txt | sort -t'|' -k1)
  • Primeiro arquivo: substitua o separador ,por |e classifique o arquivo no segundo campo
  • Segundo arquivo: substitua o separador (dois espaços) por |e classifique no primeiro campo
  • Junte os arquivos no campo hash

Saída:

3f1dfd39e88e00477483dfd578d5284f5490a0a5|artist'ssomesong.mp3|/path/to/my new music/album.wav
55a5fdde4843fc2f9d9e691cb658b6389d698b22|hello(previous one).sh|/path/to/scripts,regexs/hello(previous one).sh

Em seguida, use awkpara testar se o nome do arquivo do campo2 está presente como nome do arquivo no último campo. Se for verdade, imprima o último campo com um separador NUL e canalize o resultado para xargscopiar os arquivos para o diretório de destino.

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

Opções de cópia:

  • -nnão sobrescreva arquivos existentes
  • -tdiretório de destino

Como roteiro:

#!/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"

Execute-o como:

./script.sh list1 list2 /path/to/destination

informação relacionada