function tail() {
shift 1
echo $@
}
% tail one two three
two three
Como posso escrever o oposto desta função simples?
Eu quero alcançar
% init one two three
one two
e obter todos os argumentos, exceto o último, na $@
variável, para que a função possa ser escrita como
function init() {
# ???
echo $@
}
Eu tentei unset '@[-1]'
, unset '[@:-1]'
, de https://unix.stackexchange.com/a/611717/696135 mas estes não funcionam
Eu tentei set -- "${@:1:$(($#-1))}"
, unset "@[${#@[@]}-1]"
, set -- "${@:1:$#-1}"
de https://stackoverflow.com/questions/20398499/remove-last-argument-from-argument-list-of-shell-script-bash mas eles não funcionam
Um exemplo de um script que não funciona:
function init() {
set -- ${@:1:$#-1}
echo $@
}
init one two three
shift -p
removerá o último elemento da matriz, conformeman zshbuiltins
:Sua função desejada
init
pode ser:Como @Gairfowl disse nos comentários, em
zsh
, você faria:Para remover o último argumento (substituÃ-lo por uma lista vazia).
Até
Ou ainda:
Às vezes pode ser preferÃvel a
shift
(abreviação deshift 1
, abreviação deshift 1 argv
, sendo este último especÃfico do zsh), pois não reclama se$argv
não tiver elemento.Observe que seu:
Deveria ser escrito:
Ou compatÃvel com Korn:
Se o objetivo é imprimir os argumentos restantes, separados por espaços e seguidos por uma nova linha.
Sem as aspas, argumentos vazios seriam ignorados; sem
-
, isso não funcionaria corretamente se o primeiro argumento começasse com-
; sem-E
/-r
, não funcionaria corretamente para argumentos contendo barras invertidas.Para o seu
init
:Embora você também possa fazer¹:
O Zsh também adicionou recentemente a
${array:offset:length}
forma alternativa de fatiamento de array para compatibilidade com o ksh93, então uma variante compatÃvel com o ksh93 poderia ser:Observe a chave ao redor de
#
which, sem which no zsh (e unless na emulação sh ou ksh),$#-1
seria considerado como${#-}1
o comprimento do$-
parâmetro (usando o operador no estilo csh$#param
) seguido por 1.${@:1:$# - 1}
Também funcionaria.zsh
também suporta${var:offset:-length}
à la bash, então você também pode usarprint -r -- "${@:1:-1}"
.Cuidado, pois eles relatam um erro se a lista de argumentos estiver vazia, o mesmo que no ksh93 ou bash.
${@:1:#-1}
também funciona em versões atuais dezsh
, assim comoecho $(( # ))
gera o mesmo queecho $(( $# ))
, mas eu evitaria isso, pois não está documentado e#
é usado em vários operadores em expressões aritméticas. Em particular$(( #var ))
, , expande para o valor do caractere do primeiro caractere em$var
(semelhante a$(( '$var' ))
em ksh), então alguém pode argumentar que$(( #- ))
deve expandir para o valor do caractere do primeiro caractere em$-
.unset 'array[i]'
funciona no zsh para compatibilidade com o ksh, mas no ksh, os arrays não são arrays reais, mas mais como arrays associativos com chaves limitadas a números inteiros positivos, enquanto no zsh eles são arrays normais como em todos os outros shells não semelhantes ao Korn, então emular o comportamento do ksh nãounset 'array[i]'
desfaz a definição do elemento (o que não faria sentido para arrays normais), mas o define como uma string vazia, mesmo que esse seja o último elemento no array.Em
zsh
:$a[4]
ainda assim4
, os elementos não definidos foram substituÃdos pela string vazia.Comparando com ksh93 ou bash com seu design de array peculiar:
Isso (e o fato de que os Ãndices de array começam em 0 em vez de 1) é uma das razões pelas quais no ksh e seus clones (como o bash), os parâmetros posicionais não podem ser mapeados para um array (como a maioria dos outros shells, como csh, fish, rc, zsh fazem), e eu suspeito que o fato de que não é possÃvel
unset 'argv[i]'
no zsh, exceto para o último elemento (embora ele ainda não o desfaça , mas substitua pela string vazia) pode ter algo a ver com a compatibilidade do ksh.(se
,last
for omitido, é o mesmo quearray[first,first]
) é em si uma atribuição de fatia de array, semelhante ao que você pode conseguirperl
com suasplice
função , por exemplo, não se limita a desconfigurar o último elemento (comoperl
'spop
), você também pode fazer:array[1,0]=(new elements)
para inserir elementos na frente (comoperl
'sunshift
)array[3,5]=()
para remover elementos do meio.array+=(more)
ouarray[3]+=(more)
para inserir elementos no final ou depois de um determinado Ãndice.O que falta em comparação aos equivalentes do Perl é a capacidade de recuperar os elementos que são removidos ao mesmo tempo em que são removidos.
Por exemplo,
perl
para@last2 = splice @array, -2
inserir os dois últimos elementos,@last2
é preciso escrever:last2=( "${(A@)array[-2,-1]}" ); array[-2,-1]=()
(que pode ser abreviado paralast2=( $array[-2,-1] ); array[-2,-1]=()
se não houver nenhum elemento vazio que precise ser preservado).Mas estou divagando...
¹ Beware
"$@[-2,-1]"
expande para uma lista de um elemento vazio em vez de uma lista vazia. Isso não faz diferença paraprint -r --
quem imprime uma linha vazia em ambos os casos, mas no caso geral, isso pode ser indesejável e seria contornado usando"${(A)@[-2,-1]}"
. Se não houver nenhum elemento vazio que precise ser preservado,$@[-2,-1]
(sem as aspas) é o suficiente.