qual é a diferença entre 'encontrar'. e / home / user / * como uma entrada para o comando

3

Qual é a diferença entre find . e /home/user/* como uma entrada para o comando for ? Por exemplo:

for var in $(find .)
do echo "$var"
done

ou

for var in /home/user/*
do
echo "$var"
done

No primeiro caso, o comando for divide o arquivo com nomes que contêm espaços. Enquanto no segundo caso isso não acontece. Por quê?

    
por Edward Torvalds 13.11.2014 / 02:01

4 respostas

4

Esta é uma prática padrão para shells. A ordem das operações é a substituição de comando ( $(find .) ), a divisão de palavras e a expansão glob ( /home/user/* ).

Do padrão POSIX (divisão de palavras = divisão de campos; expansão glob = nome do caminho expansão):

The order of word expansion shall be as follows:

  1. Tilde expansion (see Tilde Expansion), parameter expansion (see Parameter Expansion), command substitution (see Command Substitution), and arithmetic expansion (see Arithmetic Expansion) shall be performed, beginning to end. See item 5 in Token Recognition.

  2. Field splitting (see Field Splitting) shall be performed on the portions of the fields generated by step 1, unless IFS is null.

  3. Pathname expansion (see Pathname Expansion) shall be performed, unless set -f is in effect.

  4. Quote removal (see Quote Removal) shall always be performed last.

Por esse motivo, é sempre recomendável usar globs sempre que possível, para que a divisão de palavras não interfira nos nomes dos arquivos. A construção $(find) é na verdade um exemplo de Bash Pitfall # 1 .

    
por 13.11.2014 / 02:20
4

O shell faz as coisas em ordem. $(find .) é chamado de substituição de comando. Os resultados da substituição de comando estão sujeitos:

  1. divisão de palavras
  2. expansão do nome do caminho
  3. remoção de cotação

A divisão de palavras é o que causa o problema quando há nomes de arquivos com espaços.

/home/user/* é a expansão do nome do caminho. Note que isso é o penúltimo na lista acima. Está sujeito apenas a citar a remoção.

    
por 13.11.2014 / 02:20
1

Uma diferença adicional entre os dois é que os shell globs (como /home/user/* ) geralmente não incluem "arquivos ocultos" (nomes de arquivos que começam com um ponto). Por outro lado, find corresponderá a todos os nomes de arquivos, exceto os diretórios especiais '.' e '..' (diretório atual e pai).

    
por 13.11.2014 / 04:01
0

Outra abordagem para explicá-lo: Quando * é usado, o shell sabe quais são os elementos únicos. A saída find é apenas uma cadeia longa. O shell não sabe quais são os elementos (e seus separadores).

A substituição de comandos pode ser usada de uma maneira especial com um programa que produz saída entre aspas; então o problema não apareceria. Mas, para fazer com que o shell reconheça a cotação, você precisa, e. eval , que muitas vezes torna a expressão inteira mais complicada:

eval for var in $(ls --quoting-style=shell)\; do echo '"$var"'\; done
    
por 13.11.2014 / 02:29