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 / 792896
Accepted
SheCodes
SheCodes
Asked: 2025-03-24 14:47:43 +0800 CST2025-03-24 14:47:43 +0800 CST 2025-03-24 14:47:43 +0800 CST

passando argumentos posicionais longos em script bash

  • 772

Gostaria de passar argumentos longos para o script, e referi este link . Criei este my_script:

#!/usr/bin/env bash
#
# Adapted from https://www.shellscript.sh/examples/getopt/
#
set -euo pipefail

user_type=unset
user_id=unset
country=unset
dev_env=unset
position_id=unset

usage(){
>&2 cat << EOF
Usage: $0]
   [ -a | --user_type input
   [ -b | --user_id input ]
   [ -c | --country input ] 
   [ -d | --dev_env input ]
   [ -e | --position_id input ]
EOF
exit 1
}

>&2 echo [$@] passed to script

args=$(getopt -a -o ha:b:c:d: --long help,user_type:,user_id:,country:,dev_env:,position_id: -- "$@")
if [[ $? -gt 0 ]]; then
  usage
fi

>&2 echo getopt creates [${args}]

eval set -- ${args}
while :
do
  case $1 in
    -a | --user_type)   user_type=$2    ; shift 2  ;;
    -b | --user_id)    user_id=$2     ; shift 2  ;;
    -h | --help)    usage      ; shift   ;;
    -c | --country)   country=$2   ; shift 2 ;;
    -d | --dev_env)   dev_env=$2   ; shift 2 ;;
    -e | --position_id) position_id=$2 ; shift 2 ;;
    # -- means the end of the arguments; drop this, and break out of the while loop
    --) shift; break ;;
    *) >&2 echo Unsupported option: $1
       usage ;;
  esac
done

if [[ $# -eq 0 ]]; then
  usage
fi

>&2 echo "user_type   : ${user_type}"
>&2 echo "user_id    : ${user_id} "
>&2 echo "country   : ${country}"
>&2 echo "dev_env   : ${dev_env}"
>&2 echo "position_id   : ${position_id}"
>&2 echo "$# parameter/s remaining: $@"
>&2 echo "Looping through remaining parameter/s:"
# set input field separator to keep quoted parameters together
# for example, "my input" will remain as one input
IFS=$'\n'
for param in $@; do
   >&2 echo -e "\t${param}"
done

echo "user ${user_type} with user id ${user_id} has been created with position_id $position_id"
exit 0

e no terminal tentei executá-lo como:

bash test_bash --user_type abc --user_id a1b2 --country aud --dev_env uat --position_id aFWf

Estou recebendo apenas uma mensagem de ajuda como:

[--user_type abc --user_id a1b2 --country aud --dev_env uat --position_id aFWf] passed to script
getopt creates [ --user_type 'abc' --user_id 'a1b2' --country 'aus' --dev_env 'uat' --position_id 'aFWf' --]
Usage: test_bash]
   [ -a | --user_type input
   [ -b | --user_id input ]
   [ -c | --country input ] 
   [ -d | --dev_env input ]
   [ -e | --position_id input ]

Eu tentei atualizar/alterar algumas coisas como args=getopt com algumas outras opções. Mas os argumentos não estão sendo analisados ​​pelo script. Agradeço sua ajuda antecipadamente. Obrigado.

shell-script
  • 2 2 respostas
  • 92 Views

2 respostas

  • Voted
  1. Best Answer
    Chris Davies
    2025-03-25T08:09:35+08:002025-03-25T08:09:35+08:00

    Aqui está, uma versão funcional do seu código. Vou sair de vez em quando para tentar explicar por que mudei o que mudei

    #!/bin/bash
    #
    # Adapted from https://www.shellscript.sh/examples/getopt/
    #
    

    Eu prefiro inicializar variáveis ​​para um valor vazio e, então, substituir o texto dentro das mensagens de erro, se necessário. Você user_type=unsetpoderia funcionar, definindo a variável para o texto, unsetmas isso impede testes simples mais tarde, como if [ -z "$user_type ]; then echo "the variable user_type has no value"; fi, e definitivamente quebra se o usuário fornece unsetcomo um valor literal:

    user_type=
    user_id=
    country=
    dev_env=
    position_id=
    
    usage(){
    >&2 cat << EOF
    Usage: $0]
       [ -a | --user_type input
       [ -b | --user_id input ]
       [ -c | --country input ]
       [ -d | --dev_env input ]
       [ -e | --position_id input ]
    EOF
    exit 1
    }
    

    Não faz sentido usar $@porque (a) você não colocou aspas duplas e (b) você está escrevendo uma string em vez de uma série de valores. (Procure a diferença entre $*, $@, e "$@"se você não seguir isso). Finalmente, eu disse getoptpara reportar erros em nome do seu programa. A ${0##*/}construção escolhe o nome do programa para você:

    >&2 echo "[$*] passed to script"
    
    if ! args=$(getopt -n "${0##*/}" -a -o ha:b:c:d: --long help,user_type:,user_id:,country:,dev_env:,position_id: -- "$@")
    then
      usage
    fi
    
    >&2 echo "getopt creates [$args]"
    

    Não se esqueça das aspas duplas em torno de $args:

    eval set -- "$args"
    while :
    do
      case $1 in
        -a | --user_type)   user_type=$2    ; shift 2  ;;
        -b | --user_id)    user_id=$2     ; shift 2  ;;
        -h | --help)    usage      ; shift   ;;
        -c | --country)   country=$2   ; shift 2 ;;
        -d | --dev_env)   dev_env=$2   ; shift 2 ;;
        -e | --position_id) position_id=$2 ; shift 2 ;;
        # -- means the end of the arguments; drop this, and break out of the while loop
        --) shift; break ;;
      esac
    done
    

    As shiftdeclarações (acima) comem os argumentos conforme são processados. Mas em um momento você quer imprimir os argumentos restantes, então não faz sentido fugir com um erro de uso se não houver mais nenhum. Código removido.

    Acima, removi a condição de erro em caseporque ela já é tratada diretamente por getopt.

    Nesta próxima seção, variáveis ​​como $user_typepodem ser não definidas, então elas não terão valor. Aqui o ${user_type:-<unset>}exibe <unset>se o valor é não definido/vazio:

    >&2 echo "user_type   : ${user_type:-<unset>}"
    >&2 echo "user_id    : ${user_id:-<unset>} "
    >&2 echo "country   : ${country:-<unset>}"
    >&2 echo "dev_env   : ${dev_env:-<unset>}"
    >&2 echo "position_id   : ${position_id:-<unset>}"
    >&2 echo "$# parameter/s remaining: $*"
    >&2 echo "Looping through remaining parameter/s:"
    

    Coloque aspas duplas "$@"para que as palavras sejam tratadas como elementos únicos, mesmo que originalmente contenham espaços em branco:

    # Output the remaining parameters
    for param in "$@"; do
       >&2 echo -e "\t$param"
    done
    
    echo "user ${user_type:-<unset>} with user id ${user_id:-<unset>} has been created with position_id ${position_id:-<unset>}"
    exit 0
    

    Finalmente, se o código estiver no arquivo myscript, não o execute como bash myscript. Em vez disso, defina o arquivo para ser legível/executável ( chmod a+rx myscript) e apenas execute-o diretamente ( ./myscript). A primeira linha informa ao sistema qual interpretador usar, então não há necessidade de especificar bashexplicitamente ao executá-lo.

    Exemplo:

    ./myscript --user_type abc --user_id a1b2 --country aud --dev_env uat --position_id aFWf
    
    [--user_type abc --user_id a1b2 --country aud --dev_env uat --position_id aFWf] passed to script
    getopt creates [ --user_type 'abc' --user_id 'a1b2' --country 'aud' --dev_env 'uat' --position_id 'aFWf' --]
    user_type   : abc
    user_id    : a1b2
    country   : aud
    dev_env   : uat
    position_id   : aFWf
    0 parameter/s remaining:
    Looping through remaining parameter/s:
    user abc with user id a1b2 has been created with position_id aFWf
    
    • 4
  2. CikoXp
    2025-03-24T15:55:25+08:002025-03-24T15:55:25+08:00

    Ok, vamos resolver essa questão. Desculpe pela resposta anterior, mesmo que correta, mas eu estava no trem e não tive chance de explicar bem minha solução.

    Aqui está seu código editado para funcionar como esperado:

    #!/usr/bin/env bash
    #
    # Adapted from https://www.shellscript.sh/examples/getopt/
    #
    set -euo pipefail
    
    user_type=unset
    user_id=unset
    country=unset
    dev_env=unset
    position_id=unset
    
    usage(){
    >&2 cat << EOF
    Usage: $0]
       [ -a | --user_type input
       [ -b | --user_id input ]
       [ -c | --country input ] 
       [ -d | --dev_env input ]
       [ -e | --position_id input ]
    EOF
    exit 1
    }
    
    >&2 echo [$@] passed to script
    
    args=$(getopt -a -o ha:b:c:d: --long help,user_type:,user_id:,country:,dev_env:,position_id: -- "$@")
    if [[ $? -gt 0 ]]; then
      usage
    fi
    
    >&2 echo getopt creates [${args}]
    
    eval set -- ${args}
    while :
    do
      case $1 in
        -a | --user_type)   user_type=$2    ; shift 2  ;;
        -b | --user_id)    user_id=$2     ; shift 2  ;;
        -h | --help)    usage      ; shift   ;;
        -c | --country)   country=$2   ; shift 2 ;;
        -d | --dev_env)   dev_env=$2   ; shift 2 ;;
        -e | --position_id) position_id=$2 ; shift 2 ;;
        # -- means the end of the arguments; drop this, and break out of the while loop
        --) shift; break ;;
        # *) >&2 echo Unsupported option: $1      <---- THIS LINE IS WRONG!
        #    usage ;;
      esac
    done
    
    # if [[ $# -eq 0 ]]; then  <-- THIS IF STATEMENT IS WRONG AT THIs POINT!
    #   usage
    # fi
    
    >&2 echo "user_type   : ${user_type}"
    >&2 echo "user_id    : ${user_id} "
    >&2 echo "country   : ${country}"
    >&2 echo "dev_env   : ${dev_env}"
    >&2 echo "position_id   : ${position_id}"
    >&2 echo "$# parameter/s remaining: $@"
    >&2 echo "Looping through remaining parameter/s:"
    # set input field separator to keep quoted parameters together
    # for example, "my input" will remain as one input
    IFS=$'\n'
    for param in $@; do
       >&2 echo -e "\t${param}"
    done
    
    echo "user ${user_type} with user id ${user_id} has been created with position_id $position_id"
    exit 0
    

    Aqui está o resultado:

    $ bash test_bash --user_type CUSTOMER --user_id A1B2C3D4 --country ITA --dev_env PRODUCTION --position_id UFXX78X0RN44KK65
    
    [--user_type CUSTOMER --user_id A1B2C3D4 --country ITA --dev_env PRODUCTION --position_id UFXX78X0RN44KK65] passed to script
    getopt creates [ --user_type 'CUSTOMER' --user_id 'A1B2C3D4' --country 'ITA' --dev_env 'PRODUCTION' --position_id 'UFXX78X0RN44KK65' --]
    user_type   : CUSTOMER
    user_id    : A1B2C3D4 
    country   : ITA
    dev_env   : PRODUCTION
    position_id   : UFXX78X0RN44KK65
    0 parameter/s remaining: 
    Looping through remaining parameter/s:
    user CUSTOMER with user id A1B2C3D4 has been created with position_id UFXX78X0RN44KK65
    

    Como eu disse na resposta anterior, a segunda declaração if está errada porque neste ponto não há mais argumentos, então $#corresponde a 0e o código sai com status 1 da usagefunção. Mas verificando bem seu código, antes disso, também *) >&2 echo Unsupported option: $1quebre seu código da mesma forma, na minha opinião porque no --método getopt. Seu código está cheio de maneiras de gerenciar os argumentos fornecidos e isso geralmente não é uma boa ideia. Minha sugestão é manter o código o mais limpo possível.

    Aqui está o que é realmente útil do seu código para atingir o mesmo resultado:

    #!/usr/bin/env bash
    
    error() {
      echo `basename $0`: ERROR: $@ 1>&2
      usage
    }
    
    usage() {
      echo usage: `basename $0` '
        [ -a | --user_type ]
        [ -b | --user_id ]
        [ -c | --country ] 
        [ -d | --dev_env ]
        [ -e | --position_id ]'
      exit 1
    }
    
    while [ True ]; do
      case "$1" in
        -a | --user_type) user_type=$2; shift;;
        -b | --user_id) user_id=$2; shift;;
        -c | --country) country=$2; shift;;
        -d | --dev_env) dev_env=$2; shift;;
        -e | --position_id) position_id=$2; shift;;
        -h | --help) usage "This is your help message!";;
        -*) error "Unsupported option $1";;
        *) break;;
      esac
      shift
    done
    
    echo "user_type   : $user_type"
    echo "user_id     : $user_id "
    echo "country     : $country"
    echo "dev_env     : $dev_env"
    echo "position_id : $position_id"
    
    if [[ $# -gt 0 ]]; then
      echo "$# parameter/s remaining: $@"
    fi
    
    echo "user \"$user_type\" with user id \"$user_id\" has been created with position_id \"$position_id\""
    

    Aqui está o resultado:

    $ bash test_bash --user_type CUSTOMER --user_id A1B2C3D4 --country ITA --dev_env PRODUCTION --position_id UFXX78X0RN44KK65
    user_type   : CUSTOMER
    user_id     : A1B2C3D4 
    country     : ITA
    dev_env     : PRODUCTION
    position_id : UFXX78X0RN44KK65
    user "CUSTOMER" with user id "A1B2C3D4" has been created with position_id "UFXX78X0RN44KK65"
    
    • -2

relate perguntas

  • Subtraindo a mesma coluna entre duas linhas no awk

  • Um script que imprime as linhas de um arquivo com seu comprimento [fechado]

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Dividir por delimitador e concatenar problema de string

  • MySQL Select com função IN () com array bash

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