Como copiar todas as pastas que contêm um arquivo específico

17

Quero fazer backup apenas das minhas pastas de música FLAC. Os arquivos FLAC podem ser aninhados assim dentro das pastas:

AlbumName/
├── Files/
│   ├── someSong01.flac
│   ├── someSong02.flac
├── Covers/
│   ├── someCover01.jpg
│   └── someCover02.jpg

Como copiar e mover todas as pastas do AlbumName com a estrutura e o conteúdo correspondentes que contêm algum lugar dentro de pelo menos um arquivo FLAC (presumo que isso seja suficiente para dizer: a música está no formato FLAC)

EDIT: arquivos FLAC podem ser aninhados; para que eu possa ter:

AlbumName2/
├── someSong01.flac
├── someSong02.flac
├── Covers/
│   ├── someCover01.jpg
|   └── someCover02.jpg

E eu quero copiar essas pastas com todo o seu conteúdo, não apenas os arquivos FLAC, e colar em outro diretório.

Então, se eu tiver também

AlbumName3/
├── someSong01.mp3
├── someSong02.mp3
├── Covers/
│   ├── someCover01.jpg
|   └── someHiddenSong.flac

e

AlbumName4/
├── Files/
│   ├── someSong01.mp3
│   ├── someSong02.mp3
├── Covers/
│   ├── someCover01.jpg
│   └── someCover02.jpg

Quero cp recursivamente para outro diretório AlbumName, AlbumName2 e AlbumName3, mas não AlbumName4

EDITAR: Nenhuma das respostas estava realmente fazendo o que eu quero, então acabei usando algo parecido com isto:

 find -mindepth 2 -name '*.flac' -exec dirname {} \; | awk -F "/" '{print $2}' | sort -u | while read -r dirname; do cp -r "$dirname" "backup/"; done

basicamente listo todos os arquivos flac, recupero a pasta raiz usando o awk, apago as duplicatas e faço o que quero

fricadelle
fonte
backup para onde, qual é o seu destino?
George Udosen
Apenas os arquivos flac precisam ser copiados ou pastas inteiras que tenham pelo menos um arquivo flac?
ninguém
pastas @nobody: " Como faço para copiar e mover todos de ALBUMNAME pastas com sua estrutura correspondente e conteúdo que contêm algum lugar dentro de pelo menos um arquivo FLAC "
terdon

Respostas:

19

Uma opção é usar o rsync, que copia apenas arquivos flac e preserva a estrutura de diretórios:

rsync -avzm --include=*/ --include=*.flac --exclude=* albums/ backup/
  • um arquivo
  • v detalhado
  • z comprimir durante a transferência (pode não ser útil copiar no mesmo computador)
  • m podar dirs vazios
  • primeiro incluir inclui todos os diretórios
  • segundo incluir inclui arquivos flac
  • a última exclusão exclui todos os outros arquivos
ninguém
fonte
Verdade? Eu entendo, ele quer preservar a estrutura de diretórios. Ele diz: "Como copio e movo todas as pastas do AlbumName com sua estrutura e conteúdo correspondentes ...".
Ninguém
2
Ah eu vejo. Não tenho certeza. Apenas os arquivos flac precisam ser copiados ou pastas inteiras que tenham pelo menos um arquivo flac?
ninguém
A questão é editada e agora explica com mais detalhes o que a fricadelle deseja. Tendo em conta que todo o conteúdo deve ser copiado, se houver um arquivo flac, minha resposta está errada, pois ele copia apenas arquivos flac. No entanto, ainda pode ser útil para outros fins.
ninguém
9

oi meu amigo voce pode usar

mkdir newdirectory
cp -r --parents */*.flac newdirectory/
amir.m ghazanfari
fonte
2
Bom nunca usado --parentsantes!
George Udosen
4
Por favor, explique isso */*.flac! cp -r --parents AlbumName/ newdirectory/Não será suficiente?
George Udosen
3
Da pergunta, parece que os flacs podem ou não estar em diretórios aninhados, então eu recomendo ativar o globstar ( shopt -s globstar) e usá-lo **/*.flacpara o glob. A estrela dupla corresponderá a zero ou mais diretórios.
wjandrea
você é wjandrea exatamente certo, deixe-me editar a minha pergunta então todo mundo entende
fricadelle
5

Boas respostas

Quero adicionar mais uma maneira, você também pode usar uma combinação de find e cpio

find . -name "*.flac" -print0|cpio --null -pdm destination/

Explicação:

GNU find searches the directory tree rooted at each given file name by evaluating the given expression from left to right, according to the rules of precedence (see Operators), until the outcome is known (the left-hand side is false for AND operations, true for OR), at which point find moves on to the next file name.

GNU cpio is a tool for creating and extracting archives, or copying files from one place to another. It handles a number of cpio formats as well as reading and writing tar files.

Existem 3 modos de cpio:

  • Modo de cópia: In copy-out mode, cpio copies files into an archive. It reads a list of filenames, one per line, on the standard input, and writes the archive onto the standard output.

  • Modo de cópia: In copy-in mode, cpio copies files out of an archive or lists the archive contents. It reads the archive from the standard input.

  • Modo de cópia-passe: In copy-pass mode, cpio copies files from one directory tree to another, combining the copy-out and copy-in steps without actually using an archive. It reads the list of files to copy from the standard input; the directory into which it will copy them is given as a non-option argument.

Aqui, estamos usando o modo Copy-pass.

  • Opções usadas no comando acima:

encontrar:

  • -name -> filename ou use regex em vez de escrever o nome completo

cpio:

  • '-m, --preserve-modification-time' Retain previous file modification times when creating files.
  • '-p, - passagem' Run in copy-pass mode. see ``Copy-pass mode``.
  • '-d, --make-directory' Create leading directories where needed.'
  • --quiet' Não imprima o número de blocos copiados.

New options are the "-print0" available with GNU find, combined with the "--null" option of cpio. These two options act together to send file names between find and cpio, even if special characters are embedded in the file names.

Também é possível usar rsyncou escrever um script de shell para encontrar e copiar arquivos com a estrutura de diretórios.

Para explicação Rsync, por favor, dê uma olhada nas respostas acima.

bsdboy
fonte
2
Você pode melhorar sua resposta incluindo explicações sobre os comandos e as opções sugeridas. - Do comentário
J. Starnes
@dessert sim, certo. Obrigado pela sua sugestão perfeita.
bsdboy
4

Resposta 1: Você também pode usar o findcomando para o mesmo.

mkdir newDir && find AlbumName/ -iname "*.flac" -exec cp --parents "{}" newDir/ \;

Explicação:

mkdircria um novo diretório. findO comando localiza *.flacarquivos localizados na AlbumNamepasta execO comando executa o cpcomando para cada nome de arquivo quefind retornado.

Resposta 2: Você também pode usar o findcomando xargstambém

mkdir newDir && find AlbumName/ -iname "*.flac" | xargs -I{} cp --parents {} newDir/

Mais informações: find , xargs

mf_starboi_8041
fonte
1
find | xargsquebrará nomes de arquivos com espaços, em find -print0 | xargs -0vez disso , use .
dessert
Eu tentei com o 1 2.flacarquivo que tem espaço no nome do arquivo. Você pode me informar o nome do arquivo em que find | xargsfalha?
precisa saber é o seguinte
veja por exemplo aqui
sobremesa
Eu não sei, mas eu sou capaz de copiar o arquivo com nome longo, que tem espaço contido nele, sem o uso defind -print0 | xargs -0
mf_starboi_8041
Tente touch "a space" && find . | xargs ls.
dessert
0

Só tive que resolver o mesmo problema para minha biblioteca de músicas e resolvi-o usando o seguinte script adaptado. Eu não o projetei totalmente com variáveis ​​ie, pois pretendo usá-lo apenas uma vez :).

O script move todos os diretórios que contêm arquivos flac, incluindo todos os outros arquivos e subdiretórios, para um novo local usando rsync. O rsync permite que você retome o script se ele parar durante o processo.

A estrutura da minha biblioteca:

library
|-artist
  |- album 1 (mp3)
  |- album 2 (flac)

Nova estrutura de biblioteca:

library
|-artist
  |- album 1 (mp3)

library-lossless
|-artist
  |- album 2 (flac)

(1) inicie o seguinte script de shell no destino SOURCE (substitua TARGET pelo respectivo diretório de sua escolha - eu apenas usei o caminho absoluto)

linha 1: encontre todos os diretórios que contêm arquivos flac e pipe (|) que estão na
linha 2 da classificação : remova duplicados com a classificação e o canal que fazem parte da
linha 3 do loop do para cada diretório da
linha 4: mostre o diretório na
linha 5 do processo : rsync no diretório de destino, além de remover a origem e preservar a estrutura (-R) na
linha 6 do local de destino : remover o diretório vazio (como o rsync remove apenas os arquivos)

find . -type f -name \*.flac -printf "%h\n" | 
sort -u | 
while read -r dirname; do
    echo $dirname
    rsync -azvm -R --remove-source-files "${dirname}" TARGET
    find "${dirname}" -type d -delete
done

(2) após a execução bem-sucedida do script em (1), você pode executar o seguinte comando no diretório de origem

find . -depth -type d -empty -delete

Este comando exclui todos os diretórios vazios não excluídos no script. Ou seja, diretórios "Artista", onde todas as subpastas / álbuns incluíam arquivos flac.

wundabua
fonte