Copiando arquivos baseados na lista de entrada, caracteres especiais em nomes de arquivos

1

Isso se baseia na pergunta aqui .

Problema :

  • Eu tenho um arquivo .txt que lista os nomes dos arquivos que eu quero copiar para a pasta newfolder no shell (Mac Terminal).

Abordagem , onde filelist.txt contém nomes de arquivos (separados por \ n), que eu quero copiar:

# version 1
for file in $(cat filelist.txt); do cp "$file" newfolder; done

Erros:

Se eu tiver nomes de arquivos em filelist.txt que contenham traços, espaço em branco, etc, os nomes serão divididos e eu obtenho corretamente um erro No such file .

Aqui está como eu tento endereçá-lo (adicionando aspas à variável):

# version 2
for file in "$(cat filelist.txt)"; do cp "$file" newfolder; done

Mas isso imprime todos os nomes de arquivos (sem divisão no espaço em branco) e não copia nada.

Perguntas:

  • Adicionar as cotações acima resolve o problema de divisão de nome. quando eu o alimento para echo ; por que não funciona para cp ?

  • Qual é a maneira correta de fazer isso com cat e cp ? Um comentário na resposta acima sugere o seguinte:

    set -f;IFS=$'\n'

que corrige as coisas, mas não sei o que faz.

Quaisquer sugestões são muito apreciadas!

    
por patrick 10.08.2018 / 19:59

1 resposta

3

Existem várias opções; este é um:

cat filelist.txt | while read file; do
    cp "$file" newfolder
done

Então, primeiro porque

for file in $(cat filelist.txt); do cp "$file" newfolder; done

não funciona? Suponha que sua lista de arquivos contenha

a
b c

O $(cat filelist.txt) produz uma lista de nomes de arquivos. O loop for vê a saída de cat e interpreta como:

for file in a b c ; do

que claramente não é a intenção.

É aqui que o comentário sobre o Separador do campo de entrada ajuda. Normalmente, o IFS é qualquer espaço em branco e, portanto, um espaço no nome do arquivo será interpretado como uma separação entre nomes de arquivos. Se você definir o IFS explicitamente como uma nova linha, o espaço não será mais visto como um separador.

for file in "$(cat filelist.txt)"; do cp "$file" newfolder; done

cria um único argumento para o loop for. O resultado é equivalente a:

for file in "a b c" ; do

e, portanto, o loop é executado apenas uma vez, com um nome de arquivo que não existe.

    
por 10.08.2018 / 20:28