AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 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

在 Bash 脚本中传递长位置参数

  • 772

我想向脚本传递长参数,并参考此链接。我创建了这个 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

并在终端上尝试运行它:

bash test_bash --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 '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 ]

我尝试更新/更改一些东西,比如 args=getopt 和其他几个选项。但我的参数没有被脚本解析。提前感谢您的帮助。谢谢。

shell-script
  • 2 2 个回答
  • 92 Views

2 个回答

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

    这是你的代码的工作版本。我会时不时地尝试解释我为什么改变了这些内容

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

    我更喜欢将变量初始化为空值,然后在必要时替换错误消息中的文本。你user_type=unset可以将变量设置为文本,unset但它会阻止以后的简单测试,例如if [ -z "$user_type ]; then echo "the variable user_type has no value"; fi,如果用户提供unset文字值,则肯定会中断:

    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
    }
    

    没有意义使用$@,因为 (a) 你没有用双引号括起来,并且 (b) 你写的是字符串而不是一系列值。(如果你不明白这一点,请查找、和之间的区别)。最后,我告诉你$*代表$@你的程序报告错误。构造会为你挑选程序名称:"$@"getopt${0##*/}

    >&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]"
    

    不要忘记双引号$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
    

    上面的语句shift在处理参数时会消耗它们。但一会儿你想打印剩余的参数,所以如果没有剩余参数,那么使用错误就毫无意义了。代码已删除。

    另外,我已经删除了中的错误条件,case因为它已经由直接处理getopt。

    在下一节中,诸如 之类的变量$user_type可能未设置,因此它们没有值。如果值未设置/为空,则${user_type:-<unset>}显示以下内容:<unset>

    >&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:"
    

    双引号,"$@"这样即使单词最初包含空格,也会被视为单个元素:

    # 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
    

    最后,如果代码在文件 中myscript,请不要将其作为 运行bash myscript。而是将文件设置为可读/可执行 ( chmod a+rx myscript) 并直接运行它 ( )。第一行告诉系统要使用哪个解释器,因此运行时./myscript无需明确指定。bash

    例子:

    ./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

    好吧,让我们来解决这个问题。抱歉,之前的回答虽然正确,但我当时在火车上,没有机会很好地解释我的解决方案。

    她的代码已编辑,可以按预期工作:

    #!/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
    

    结果如下:

    $ 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
    

    正如我在上一个回答中所说,第二个 if 语句是错误的,因为此时没有更多参数,因此$#对应于0并且代码以状态 1 从usage函数退出。但在此之前,请仔细检查您的代码,*) >&2 echo Unsupported option: $1在我看来,这也是以同样的方式破坏您的代码的原因,因为--在getopt方法中。您的代码充满了管理给定参数的方法,这通常不是一个好主意。我的建议是尽可能保持代码干净。

    以下是您代码中真正有用的实现相同结果的方法:

    #!/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\""
    

    结果如下:

    $ 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

相关问题

  • 在awk中的两行之间减去相同的列

  • 打印文件行及其长度的脚本[关闭]

  • 通过命令的标准输出以编程方式导出环境变量[重复]

  • 按分隔符拆分并连接字符串问题

  • MySQL Select with function IN () with bash array

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

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

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve