AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 789120
Accepted
Nils
Nils
Asked: 2025-01-06 07:32:45 +0800 CST2025-01-06 07:32:45 +0800 CST 2025-01-06 07:32:45 +0800 CST

Como fazer o oposto de shift no zsh?

  • 772
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
zsh
  • 2 2 respostas
  • 916 Views

2 respostas

  • Voted
  1. Best Answer
    rowboat
    2025-01-06T21:41:17+08:002025-01-06T21:41:17+08:00

    shift -premoverá o último elemento da matriz, conforme man zshbuiltins:

    shift [ -p ] [ n ] [ name ... ]

    Os parâmetros posicionais ${n+1} ... são renomeados para $1 ..., onde n é uma expressão aritmética cujo padrão é 1. Se algum nome for fornecido, as matrizes com esses nomes serão deslocadas em vez dos parâmetros posicionais.

    Se a opção -p for fornecida, os argumentos serão removidos (removidos) do final em vez do início do array.

    Sua função desejada initpode ser:

    function init {
        shift -p
        print -r -- "$@"
    }
    
    • 12
  2. Stéphane Chazelas
    2025-01-06T16:19:06+08:002025-01-06T16:19:06+08:00

    Como @Gairfowl disse nos comentários, em zsh, você faria:

    argv[-1]=()
    

    Para remover o último argumento (substituí-lo por uma lista vazia).

    Até

    argv[1]=()
    

    Ou ainda:

    1=()
    

    Às vezes pode ser preferível a shift(abreviação de shift 1, abreviação de shift 1 argv, sendo este último específico do zsh), pois não reclama se $argvnão tiver elemento.

    Observe que seu:

    function tail() {
        shift 1
        echo $@
    }
    

    Deveria ser escrito:

    tail() {
      (( $# == 0 )) || shift
      echo -E - "$@"
    }
    

    Ou compatível com Korn:

    function tail {
      (( $# == 0 )) || shift
      print -r - "$@"
    }
    

    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:

    init() {
      argv[-1]=()
      print -r -- "$@"
    }
    

    Embora você também possa fazer¹:

    init() print -r -- "$@[1,-2]"
    

    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:

    function init {
      print -r -- "${@:1:${#}-1}"
    }
    

    Observe a chave ao redor de #which, sem which no zsh (e unless na emulação sh ou ksh), $#-1seria considerado como ${#-}1o comprimento do $-parâmetro (usando o operador no estilo csh $#param) seguido por 1. ${@:1:$# - 1}Também funcionaria.

    zshtambém suporta ${var:offset:-length}à la bash, então você também pode usar print -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 de zsh, assim como echo $(( # ))gera o mesmo que echo $(( $# )), 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=({1..5})
    $ unset 'a[3]' 'a[-1]'
    $ print -r - $a[4]
    4
    $ typeset -p a
    typeset -a a=( 1 2 '' 4 '' )
    

    $a[4]ainda assim 4, os elementos não definidos foram substituídos pela string vazia.

    Comparando com ksh93 ou bash com seu design de array peculiar:

    $ a=({0..5})
    $ unset 'a[3]' 'a[-1]'
    $ print -r - "${a[4]}"
    4
    $ typeset -p a
    typeset -a a=([0]=0 [1]=1 [2]=2 [4]=4)
    

    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.

    array[first,last]=(new values)
    

    (se ,lastfor omitido, é o mesmo que array[first,first]) é em si uma atribuição de fatia de array, semelhante ao que você pode conseguir perlcom sua splicefunção , por exemplo, não se limita a desconfigurar o último elemento (como perl's pop), você também pode fazer:

    • array[1,0]=(new elements)para inserir elementos na frente (como perl's unshift)
    • array[3,5]=()para remover elementos do meio.
    • array+=(more)ou array[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, perlpara @last2 = splice @array, -2inserir os dois últimos elementos, @last2é preciso escrever: last2=( "${(A@)array[-2,-1]}" ); array[-2,-1]=()(que pode ser abreviado para last2=( $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 para print -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.

    • 9

relate perguntas

  • Listar arquivos que não possuem outro arquivo com sufixo

  • Em que circunstâncias o executável encontrado primeiro no caminho não será usado

  • Symlinking para todos os arquivos de ponto e diretórios

  • Como incrementar uma variável nomeada dinamicamente em `zsh`

  • Por que não consigo definir uma variável somente leitura chamada path no zsh?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve