Geralmente usamos $@
para representar todo o argumento, exceto $ 0. No entanto, não sei o que $@
é estrutura de dados .
Por que se comporta de maneira diferente $*
ao incluir aspas duplas, alguém poderia me dar uma explicação em nível de intérprete?
Ele pode ser iterado no loop for, portanto parece ser um array. No entanto, ele também pode ecoar totalmente com o simples echo $@
, se for uma matriz, apenas o primeiro elemento será mostrado. Devido à limitação do shell, não posso escrever mais código do experimento para executá-lo.
Diferença entre este post : Este post mostra como $@
se comporta de maneira diferente $*
. Mas eu estou querendo saber sobre o tipo de dados de $@
. O shell como uma linguagem de interpretação, como Python, deve representar dados de acordo com uma série de tipos fundamentais. Ou, em outras palavras, quero saber como $ @ é armazenado na memória do computador.
É uma string, uma string com várias linhas ou uma matriz?
Se for um tipo de dados exclusivo, é possível definir uma variável personalizada como uma instância desse tipo?
printf '%s\n' "$@"
eprintf '%s\n' "$*"
. Oecho
utilitário apenas exibe seus argumentos, não importa se eles são um ou muitos. Ambas são matrizes (de cadeias), mas se comportam de maneira diferente quando são citadas duas vezes. Se um deles fosse uma sequência de linhas múltiplas, eles não seriam capazes de armazenar sequências de linhas múltiplas (o que podem). Não está claro qual problema você está tentando resolver.@var
variável no Perl, em termos de armazenamento subjacente. Do ponto de vista de um programa Perl comum, isso realmente não importa, além de ser acessível como uma matriz / lista (e pelo fato de haver contextos nos quais uma lista é esperada).Respostas:
Isso começou como um hack no shell Bourne. No shell Bourne, a divisão de palavras do IFS foi realizada (após a tokenização) em todas as palavras no contexto da lista (argumentos da linha de comando ou nas palavras em que os
for
loops se repetem). Se você tinha:Essa segunda linha seria tokenised em 3 palavras,
$var
seria ampliado, e dividir + glob seria feito em todas as três palavras, então você iria acabar correndoed
comt
,f
,le.txt
,f
,le2.txt
como argumentos.Citar partes disso impediria a divisão + glob. O shell Bourne inicialmente lembrou quais caracteres foram citados, definindo o 8º bit neles internamente (que mudou mais tarde quando o Unix ficou 8 bits limpo, mas o shell ainda fazia algo semelhante para lembrar qual byte era mencionado).
Ambos
$*
e$@
foram a concatenação dos parâmetros posicionais com o espaço intermediário. Mas havia um processamento especial de$@
quando estava entre aspas duplas. Se$1
continhafoo bar
e$2
continhabaz
,"$@"
expandiria para:(com os
^
s acima indicando quais dos caracteres têm o oitavo bit definido). Onde o primeiro espaço foi citado (o oitavo bit foi definido), mas não o segundo (o que foi adicionado entre as palavras).E é a divisão do IFS que cuida da separação dos argumentos (assumindo que o caractere de espaço esteja
$IFS
como está por padrão). É semelhante ao modo como$*
foi expandido em seu antecessor o shell Mashey (ele próprio baseado no shell Thomson, enquanto o shell Bourne foi escrito do zero).Isso explica por que, no shell Bourne, inicialmente
"$@"
seria expandido para a cadeia vazia, em vez de nada quando a lista de parâmetros posicionais estava vazia (era necessário contornar isso${1+"$@"}
), por que não mantinha os parâmetros posicionais vazios e por que"$@"
não funcionou quando$IFS
não continha o caractere de espaço.A intenção era poder passar a lista de argumentos literalmente para outro comando, mas isso não funcionava corretamente para a lista vazia, para elementos vazios ou quando
$IFS
não continham espaço (os dois primeiros problemas foram corrigidos em versões posteriores )O shell Korn (no qual a especificação POSIX se baseia) mudou esse comportamento de algumas maneiras:
edit
oufile.txt
no exemplo acima)$*
e$@
são unidos ao primeiro caractere de$IFS
ou espaço quando$IFS
está vazio, exceto que para um citado"$@"
, esse marceneiro não é citado como no shell Bourne e, para um citado"$*"
quandoIFS
está vazio, os parâmetros posicionais são anexados sem separador.${array[@]}
${array[*]}
lembrando as de Bourne$*
e$@
começando no índice 0 em vez de 1, e esparsas (mais parecidas com matrizes associativas), o que significa que$@
realmente não podem ser tratadas como uma matriz ksh (compare comcsh
/rc
/zsh
/fish
/ /yash
where$argv
/$*
são normais matrizes)."$@"
Quando$#
0 é agora expandido para nada em vez da cadeia vazia,"$@"
funciona quando$IFS
não contém espaços, exceto quandoIFS
está vazio. Um$*
sem aspas sem curingas se expande para um argumento (onde os parâmetros posicionais são unidos com espaço) quando$IFS
está vazio.O ksh93 corrigiu os problemas restantes acima. Em ksh93,
$*
e se$@
expande para a lista de parâmetros posicionais, separados independentemente do valor de$IFS
, e depois divididos + globbed + brace-expandido em contextos de lista,$*
unidos ao primeiro byte (não caractere) de$IFS
,"$@"
em contextos de lista se expandem para a lista de parâmetros posicionais, independentemente do valor de$IFS
. No contexto de não lista, como emvar=$@
,$@
é associado o espaço, independentemente do valor de$IFS
.bash
As matrizes são projetadas após as ksh. As diferenças são:$IFS
vez de para byte$*
quando não citado no contexto de não lista quando$IFS
está vazio.Enquanto a especificação POSIX costumava ser bastante vaga, agora mais ou menos especifica o comportamento do bash.
É diferente de matrizes normais
ksh
oubash
em que:"${@:0}"
que inclui$0
(não é um parâmetro posicional, e em funções fornece o nome da função ou não, dependendo do shell e como a função foi definida)).shift
pode ser usado.Em
zsh
ouyash
onde matrizes são matrizes normais (não esparsas, os índices começam em um como em todos os outros shells, exceto ksh / bash),$*
é tratado como uma matriz normal.zsh
tem$argv
como um apelido para ele (para compatibilidade comcsh
).$*
é o mesmo que$argv
ou${argv[*]}
(argumentos associados ao primeiro caractere de,$IFS
mas ainda separados em contextos de lista)."$@"
gosta"${argv[@]}"
ou"${*[@]}"}
passa pelo processamento especial no estilo Korn.fonte
É um parâmetro especial que se expande para os valores dos parâmetros posicionais ... Mas isso é bastante detalhado sobre a terminologia.
Podemos visualizar os parâmetros posicionais como partes de
$@
, para que ele tenha vários elementos distintos ($1
,$2
...), que podem ser acessados independentemente e são nomeados por números naturais consecutivos. Isso torna algo que geralmente é chamado de matriz.A sintaxe é um pouco estranha e até limitada. Não há como modificar um único elemento da matriz individualmente. Em vez disso, tudo deve ser definido de uma só vez. (Você pode usar
set -- "$@" foo
para acrescentar um valor ouset -- "${@:1:2}" foo "${@:3}"
adicionar um valor no meio. Mas nos dois casos, você deve escrever a lista resultante inteira.)Porque eles são definidos para se comportar de maneira diferente.
Se você quer dizer o fato de que
a=(foo bar asdf); echo $a
a saída será justafoo
, isso é principalmente uma sintaxe da sintaxe do shell, e o fato de que as matrizes nomeadas no estilo ksh foram criadas depois dos parâmetros posicionais e$@
. Simples$a
é o mesmo${a[0]}
que tem o significado compatível com versões anteriores de um único valor escalar, independentemente de sea
ser uma matriz ou uma variável escalar simples.O
@
sinal referente à lista inteira foi reutilizado com matrizes nomeadas, e"${a[@]}"
é assim que se obtém a lista inteira. Comparado às matrizes nomeadas, com$@
, os colchetes e colchetes desnecessários e o nome são ignorados.Isso depende da implementação, você terá que procurar o código-fonte de qualquer shell em particular que lhe interesse.
Uma matriz, principalmente. Embora sejam diferentes dos arrays nomeados no estilo ksh, pois eles podem ter números inteiros não negativos arbitrários como índices, e não apenas números consecutivos
$@
. (Ou seja, uma matriz chamada pode ser escassa, e têm por exemplo, os índices1
,3
e4
, com0
e2
faltando. Isso não é possível com os parâmetros de posição.)Não é uma string única, pois pode ser expandida para elementos distintos, e chamar as linhas de elementos também não é correto, pois qualquer variável regular ou um dos parâmetros posicionais (elementos de
$@
) também pode conter novas linhas.Não. Mas matrizes nomeadas são provavelmente mais úteis de qualquer maneira.
fonte
$@
não é uma estrutura de dados, é uma das poucas funções / operadores para expandir a estrutura de dados de parâmetros posicionais.