A divisão de palavras se aplica apenas a expansões sem aspas (expansão de parâmetros, expansão aritmética e substituição de comandos) em shells modernos semelhantes a Bourne (em zsh
, somente substituição de comando, a menos que você use um modo de emulação).
Quando você faz:
args a :b
A divisão de palavras não está envolvida de todo.
É a análise de shell que simboliza esses, descobre que o primeiro não é uma de suas palavras-chave e, portanto, é um comando simples com três argumentos: args
, a
e :b
. A quantidade de espaço não fará diferença lá. Observe que não são apenas espaços, também guias e, em alguns shells (como yash
ou bash
), qualquer caractere considerado em branco em sua localidade (embora no caso de bash
, não os multibyte) ¹.
Mesmo no shell Bourne, onde a divisão de palavras também se aplicava a argumentos não citados de comandos, independentemente de serem ou não o resultado de expansões, isso seria feito no topo (long after). análise de sintaxe.
No shell Bourne, em
IFS=i
while bib=did edit foo
Isso não seria analisar como:
"wh" "le b" "b=d" "d ed" "t foo"
Mas primeiro como while
com um comando simples e a edit
word (como é um argumento, mas não a bid=did
word que é uma atribuição) desse comando simples seria mais dividido em ed
e t
para que o comando ed
com os 3 argumentos ed
, t
e foo
seja executado como a condição desse loop while
.
A divisão de palavras não é parte da análise de sintaxe. É como um operador que é aplicado implicitamente a argumentos (também em for
loop words, arrays e com algum shell o alvo de redirecionamentos e alguns outros contextos ) para as partes deles que não são citadas. O que é confuso é que é feito implicitamente . Você não usa cmd split($x)
, você cmd $x
e split()
( realmente glob(split())
) estão implícitos. Em zsh
, você precisa solicitá-lo explicitamente para expansões de parâmetros ( split($x)
is $=x
there ( $=
parecendo um par de tesouras)).
Agora, para seus exemplos:
Os argumentosargs(){ echo ["$*"];} args a :b # three spaces # [a::b]
a
e :b
de args
se juntaram ao primeiro caractere de $IFS
, o que dá a::b
(note que é uma má idéia usar [...]
aqui, pois é um operador globbing). / p>
args(){ echo [$*];} args a :b # three spaces # [a b] # two spaces
$*
(que contém a::b
) é dividido em a
, a string vazia e b
. Então é:
echo '[a' '' 'b]'
args(){ echo ["$1"]["$2"]; } args a :b # three spaces # [a][:b]
não é surpresa como não dividir palavras.
args(){ echo [$1][$2]; } args a :b # three spaces # [a][ b]
Isso é como:
echo '[a]' '[' 'b]'
como $2
( :b
) seria dividido na string vazia e b
.
Um caso em que você verá variações entre implementações é quando $IFS
está vazio.
Em:
set a b
IFS=
printf '<%s>\n' $*
Em algumas conchas (a maioria hoje em dia), você vê
<a>
<b>
E não <ab>
, embora "$*"
seja expandido para ab
. Esses shells ainda separam os parâmetros a
e b
position e agora foi feito um requisito POSIX na última versão do padrão.
Se você fez:
set a b
IFS=
var="$*" # note that the behaviour for var=$* is unspecified
printf '<%s>\n' $var
você veria <ab>
como as informações que a
e b
eram 2 argumentos separados foram perdidos quando atribuídos a $var
.
¹, é claro, não são apenas espaços em branco que delimitam palavras. Tokens especiais na sintaxe do shell também, cuja lista depende do contexto. Na maioria dos contextos, |
, ||
, &
, ;
, nova linha, <
, >
, >>
... delimitam palavras. Em ksh93
, por exemplo, você pode escrever um comando em branco como:
while({([[(:)]])})&&((1||1))do(:);uname<&2|tee>(rev)file;done