De man bash
EXPANSION Expansion is performed on the command line after it has been split into words. There are seven kinds of expansion performed: brace expansion, tilde expansion, parameter and variable expansion, command substitution, arithmetic expansion, word splitting, and pathname expansion. The order of expansions is: brace expansion, tilde expansion, parameter, variable and arithmetic expansion and command substitution (done in a left-to-right fashion), word splitting, and pathname expansion.
array=( $names )
O motivo de 4 entradas é porque um parâmetro $names
sem aspas está sujeito a divisão de palavras com base no separador de campos interno IFS
, que por padrão é <space><tab><newline>
. Se você fosse citar "$names"
para inibir a divisão de palavras, você só obteria um elemento de matriz com o valor f 1 f 2
, mais uma vez não o que você deseja.
array=( * )
O acima, por outro lado, está sujeito somente à expansão do nome do caminho , que é a última expansão realizada. Os resultados não estão sujeitos à divisão de palavras, assim você obtém os 2 elementos desejados.
Se você deseja fazer array=( $names )
work, precisará separar os nomes de arquivos de alguma forma por um caractere não-espacial que também não esteja contido nos nomes dos arquivos. Você precisará então configurar o IFS para esse caractere.
$ names=$(echo f* | sed "s/ /#/2")
$ echo $names
f 1#f 2
$ IFS='#' array=( $names )
$ echo ${#array[@]}
2
$ echo ${array[0]}
f 1
Uma maneira mais elegante de fazer isso seria usar o byte
do NUL como o delimitador de nome de arquivo, já que é garantido que ele nunca ficará separado de um nome de arquivo. Para fazer isso, precisaremos usar o comando find
-print0
com seu sinal read
, bem como o IFS
incorporado no NUL. Nós também precisamos limpar o IFS para que nenhuma divisão de palavras em espaços seja realizada.
#!/bin/bash
unset array
while IFS= read -r -d $'$ touch f{1,2}; IFS="#"; rm f1#f2
rm: cannot remove 'f1#f2': No such file or directory
' name; do
array+=( "$name" )
done < <(find . -type f -name "f*" -print0 )
Atualizar
Expansion is performed on the command line after it has been split into words.
Eu posso ver como alguém ficaria confuso com a citação acima apenas para afirmar que divisão de palavras é a segunda à última expansão a ocorrer.
Uma maneira melhor de traduzir essa frase na minha opinião seria:
Expansion is performed on the command line after it has been split into arguments.
A divisão de argumentos no shell é feita sempre pelo espaço em branco, e são esses argumentos que estão sujeitos a expansão. Se você quer ter espaço em branco em seu argumento, você deve usar Quoting ou Escapando . IFS
não aumenta a divisão de argumentos, apenas a divisão de palavras.
Considere este exemplo:
array=( $names )
Observe como a configuração #
to f1#f2
não alterou o fato de que o shell ainda só viu um argumento %code% ; que a propósito está então sujeito às várias expansões.
Eu recomendaria muito seu aquatint com o BashFAQ se você ainda não o fez. Em particular, sugiro strongmente que você leia as seguintes duas entradas suplementares: