Copie a lista de arquivos

26

Eu tenho uma lista de arquivos separados por espaços em um arquivo list.txt . Eu gostaria de copiá-los para uma nova pasta.

Eu tentei fazer:

cp 'cat list.txt' new_folder

mas não funcionou.

Como você faria isso?

Atualização:

Obrigado por todas as suas respostas muito interessantes. Eu não pedi tanto assim:)

Após ter tentado a solução acima uma segunda vez, parece que cp imprimiu a ajuda de uso porque a pasta new_folder ainda não existia! Desculpe, parece ser um erro estúpido ... Quando eu crio a pasta antes, funciona.

No entanto, aprendi muito com todas as suas respostas e soluções, muito obrigado pelo tempo que você dedica para escrevê-las.

    
por Klaus 24.08.2010 / 23:14

3 respostas

30

Tente usar xargs:

cat list.txt | xargs -J % cp % new_folder

Atualização:

Eu fiz isso no OS X, que tem uma versão diferente das versões GNU / Linux. O xargs que vem de GNU findutils não tem -J , mas tem -I , que é semelhante (como Dennis Williamson apontou em um comentário). A versão do xargs do OS X tem -I e -J , que têm comportamentos ligeiramente diferentes - ou funcionará para essa pergunta original.

$ cat list.txt
one
two.txt
three.rtf

$ cat list.txt | xargs -J % echo cp % new_folder
cp one two.txt three.rtf new_folder

$ cat list.txt | xargs -I % echo cp % new_folder
cp one new_folder
cp two.txt new_folder
cp three.rtf new_folder
    
por 24.08.2010 / 23:18
41

Não há necessidade de cat :

xargs -a list.txt cp -t new_folder

Ou usando opções longas:

xargs --arg-file=list.txt cp --target-directory=new_folder

Aqui estão algumas versões do shell:

Bash:

for file in $(<list.txt); do cp "$file" new_folder; done

ou

cp $(<list.txt) new_folder

sh (ou Bash):

# still no cat!
while read -r line; do for file in $line; do cp "$file" new_folder; done; done < list.txt

ou

# none here either
while read -r line; do cp $line new_folder; done < list.txt

ou

# meow
for file in $(cat list.txt); do cp "$file" new_folder; done

ou

# meow
cp $(cat list.txt) new_folder
    
por 25.08.2010 / 03:26
7

Eu tive uma resposta embaraçosa aqui antes, mas a resposta de Denis essa coisa básica, eu acho que vale a pena colocar aqui.

A pergunta original é "Eu tenho um arquivo de texto com uma lista de nomes de arquivos separados por espaços. Como posso copiá-los para um diretório de destino". A princípio, isso pode parecer complicado ou complicado, porque você acha que precisa extrair os itens do arquivo de uma maneira específica. No entanto, quando o shell processa uma linha de comando, a primeira coisa que ele faz é separar a lista de argumentos em tokens e (aqui está o bit que ninguém disse abertamente) espaços tokens separados . (As linhas novas também separam tokens, e é por isso que o teste de Doug Harris com uma lista separada por nova linha teve o mesmo resultado.) Ou seja, o shell espera e já pode manipular uma lista separada por espaço.

Portanto, tudo o que você precisa fazer aqui é colocar a lista separada por espaço (que você já possui) no lugar certo em seu comando. Seu comando é uma variação disso:

cp file1 file2 file3...file# target

A única ruga é que você deseja obter a lista de arquivos de 1 a # do seu arquivo de texto.

Como Dennis aponta em seu comentário, sua tentativa original ( cp cat list.txt new_folder ) já deveria ter funcionado. Por quê? Porque o comando interno cat list.txt é processado primeiro pelo shell e expande para file1 file2 file3...file# , que é exatamente o que o shell espera e deseja nessa parte do comando. Se não funcionasse, então (1) você tinha um erro de digitação ou (2) seus nomes de arquivos eram estranhos (eles tinham espaços ou outros caracteres incomuns).

A razão pela qual todas as respostas de Dennis funcionam é simplesmente que elas fornecem a lista necessária de arquivos para que cp trabalhe, colocando essa lista onde ela pertence em todo o comando. Novamente, o comando em si é este em estrutura:

cp list-of-files target_directory

É fácil ver como tudo isso vem junto nesta versão:

cp $(<list.txt) new_folder

$() faz com que o shell execute o comando dentro dos parênteses e, em seguida, substitua sua saída naquele ponto na linha maior . Então o shell executa a linha como um todo. A propósito, $() é uma versão mais moderna do que você já fazia com backticks ('). Próximo: < é um operador de redirecionamento de arquivos. Ele diz ao shell para descarregar o conteúdo de list.txt para a entrada padrão. Como o $() bit é processado primeiro, veja o que acontece em etapas:

  1. cp $(<list.txt) new_folder # split line into three tokens: cp, $(<list.txt), new_folder
  2. cp file1 file2 file3...file# new_folder # substitute result of $(<list.txt) into the larger command

Obviamente, o passo 2 é simplesmente o comando normal cp que você queria.

Eu percebo que estou batendo muito (talvez muito morto) cavalo, mas acho que vale a pena fazer. Entender exatamente como o shell processa um comando pode ajudá-lo a escrever melhor e simplificar muito. Ele também mostrará onde os problemas provavelmente estarão ocultos. Neste caso, por exemplo, minha primeira pergunta a você deveria ter sido sobre nomes de arquivos engraçados ou um possível erro de digitação. Nenhuma acrobacia era necessária.

    
por 24.08.2010 / 23:31

Tags