Lidando com espaços de variáveis para 'mv' [duplicado]

1
    

Esta pergunta já tem uma resposta aqui:

    

digamos que eu tenha um diretório com os seguintes arquivos / diretórios:

google
apple
mozilla foundation   # a file with spaces
browsers

Portanto, gostaria de mover os arquivos para o diretório browsers . Aqui está um script que eu escrevi:

for d in $(ls); do
    if ! [ "$d" == "browsers" ]; then
        mv "$d" "browsers"
    fi
done

Então, google e apple foram para browsers , mas recebi:

mv: cannot stat 'mozilla': No such file or directory
mv: cannot stat 'foundation': No such file or directory

Obviamente, o problema é espaços em uma variável. Qual é a maneira correta de lidar com isso?

É claro que acredito que deve haver um comando de uma linha mais elegante para fazer isso, mas gostaria de saber como devo usar variáveis com espaços.

    
por Bumsik Kim 11.08.2017 / 07:46

2 respostas

4

Fazer não nunca usar:

for d in $(ls)

Use isso:

for d in *

Dois problemas, entre outros, com o uso de $(ls) são que o shell submete os resultados de $(ls) a divisão de palavras e expansão de nome de caminho . No seu caso, foi divisão de palavras que fez com que mozilla foundation se transformasse em mozilla e foundation .

Para uma discussão mais longa sobre o motivo de não usar $(ls) , consulte "O que $(ls *.txt) do? "

Se você precisar considerar o caso em que não há nenhum arquivo não oculto no diretório (o caso em que for i in $(ls) pode parecer melhor, já que ele não passa no loop, em oposição a um passo no loop com * como $i em for i in * (exceto em zsh )), você desejaria dizer ao shell para não expandir para nada para globs não correspondentes:

  • zsh : for i in *(N)
  • ksh93 : for i in ~(N)*
  • bash4.4+ : f() { local -; shopt -s nullglob; for i in *; ...; done; }; f (o ponto é usar a opção nullglob localmente (veja também a opção failglob para um comportamento similar ao padrão por zsh )).
  • yash : set -o nullglob (e redefinir depois, não há escopo local para opções em yash até onde eu sei)
  • em outros shells, você sempre pode adicionar um [ -e "$i" ] || [ -L "$i" ] || continue no loop para verificar a existência do arquivo.
por 11.08.2017 / 07:56
1

Não analise ls result e, além da resposta de John1024, você pode usar find .

LC_ALL=C find . ! -name . -prune ! -name '.*' -type f -exec mv -t /path/to/dest {} +

(assumindo o GNU find para a opção -t , ignorando arquivos ocultos como ls ou * glob e excluindo arquivos não-regulares. Observe que a lista não está classificada (ao contrário de ls ou * ). LC_ALL=C é necessário para ignorar corretamente qualquer arquivo cujo nome inicie com . mesmo aqueles que não contiverem caracteres válidos na localidade do usuário. Isso afeta o idioma das mensagens de erro). / p>     

por 11.08.2017 / 08:10

Tags