ChatGPT解决这个技术问题 Extra ChatGPT

检查 Bash shell 脚本中是否存在输入参数

我需要检查输入参数的存在。我有以下脚本

if [ "$1" -gt "-1" ]
  then echo hi
fi

我明白了

[: : integer expression expected

如何首先检查输入参数 1 以查看它是否存在?


v
vallentin

这是:

if [ $# -eq 0 ]
  then
    echo "No arguments supplied"
fi

$# 变量将告诉您脚本传递的输入参数的数量。

或者您可以检查参数是否为空字符串,例如:

if [ -z "$1" ]
  then
    echo "No argument supplied"
fi

-z 开关将测试 "$1" 的扩展是否为空字符串。如果它是空字符串,则执行正文。


我喜欢这样做,语法简洁,而且仍然可以接受 POSIX。 [ -z "$1" ] && echo "No argument supplied" 我更喜欢单线,因为它们对我来说更容易;与使用 if 相比,检查退出值也更快
当脚本运行需要参数时,您可能希望在 if 块内的回显末尾添加一个 exit 1。显而易见,但值得注意的是完整性。
第一个参数被初始化但为空是可能的,尽管很少有用; programname "" secondarg third$# 检查明确检查参数的数量。
对于菜鸟,尤其是来自非脚本背景的人,提及这些事情的一些特殊性也很重要。您还可以提到我们需要在左大括号和右大括号之后留一个空格。否则事情不工作。我自己是一个脚本菜鸟(我来自 C 背景)并且发现它很难。只有当我决定“按原样”复制整个事情时,事情才对我有用。就在那时我意识到我必须在开口支架之后和闭合支架之前留出一个空间。
对于可选参数 if [ ! -z "$1" ]; then ...
S
Skaldebane

最好以这种方式演示

if [[ $# -eq 0 ]] ; then
    echo 'some message'
    exit 1
fi

如果参数太少,通常需要退出。


不,不是:这具有您通常想要的 exit 1,并使用 (iirc) 通常更合理的 [[ ]] 测试。因此,对于盲目复制粘贴代码的人来说,这是更好的答案。
要详细了解 [ ] 和 [[ ]] 之间的区别,请参阅 stackoverflow.com/questions/3427872/…
A
Aleks N.

在某些情况下,您需要检查用户是否将参数传递给脚本,如果没有,则回退到默认值。就像在下面的脚本中一样:

scale=${2:-1}
emulator @$1 -scale $scale

如果用户没有将 scale 作为第二个参数传递,我会默认使用 -scale 1 启动 Android 模拟器。 ${varname:-word} 是扩展运算符。还有其他扩展运算符:

${varname:=word} 设置未定义的 varname 而不是返回 word 值;

${varname:?message} 如果 varname 已定义且不为空,则返回或打印消息并中止脚本(如第一个示例);

${varname:+word} 仅当 varname 已定义且不为 null 时才返回 word;否则返回 null。


上面的示例似乎使用了 ${varname?message}。额外的 : 是拼写错误,还是会改变行为?
Eki,“:”是一个内置命令,在这个例子中是 /bin/true 的简写。它代表一个无所事事的命令,基本上忽略它提供的参数。为了防止解释器尝试执行“$varname”的内容(您当然不希望发生这种情况),在这个测试中这是必不可少的。也值得注意;您可以根据需要使用此方法测试任意数量的变量。并且都带有特定的错误消息。即: ${1?"First argument is null"} ${2?"Please provide more than 1 argument"}
K
Koen.

尝试:

 #!/bin/bash
 if [ "$#" -eq  "0" ]
   then
     echo "No arguments supplied"
 else
     echo "Hello world"
 fi

为什么 $#0 需要双引号?
如果我们使用不带双引号的 $# 和 0 就没有问题
在 Windows 上,mingw 这是唯一的方法。
这个答案为我刚刚制作的脚本提供了很好的起点。也感谢您展示 else
@user13107 bash 中的双引号变量可防止通配符(即扩展文件名,如 foo*)和分词(即,如果值包含空格,则拆分内容)。在这种情况下,没有必要引用 $#,因为这两种情况都不适用。引用 0 也不是必需的,但有些人更喜欢引用值,因为它们实际上是字符串,这使得它更加明确。
I
Iulian Onofrei

另一种检测参数是否传递给脚本的方法:

((!$#)) && echo No arguments supplied!

请注意,(( expr )) 导致表达式按照 Shell Arithmetic 的规则进行评估。

为了在没有任何参数的情况下退出,可以说:

((!$#)) && echo No arguments supplied! && exit 1

另一种(类似的)说法是:

let $# || echo No arguments supplied

let $# || { echo No arguments supplied; exit 1; }  # Exit if no arguments!

help let 说:

let: let arg [arg ...] 计算算术表达式。 ...退出状态:如果最后一个 ARG 计算结果为 0,让返回 1;否则让返回 0。


-1 如果验证参数的存在,这可能是最糟糕的方法..另外它可能会触发历史替换并可能做坏事。
而不是杀死我的 zsh 进程的 exit,我使用不会杀死它的 return
为什么 ((!$#)) 会触发历史替换?
s
seorphates

只是因为有一个更基点要指出,我会补充一点,您可以简单地测试您的字符串是否为空:

if [ "$1" ]; then
  echo yes
else
  echo no
fi

同样,如果您期望 arg 计数,只需测试您的最后一个:

if [ "$3" ]; then
  echo has args correct or not
else
  echo fixme
fi

依此类推,带有任何 arg 或 var


f
f2cx

我经常将这个片段用于简单的脚本:

#!/bin/bash

if [ -z "$1" ]; then
    echo -e "\nPlease call '$0 <argument>' to run this command!\n"
    exit 1
fi

那么,这是要用在你只需要一个参数吗?
@Danijel 不,这是测试第一个位置是否有参数。您可以有一个 $2 或 $3 参数($0 是正在运行的脚本名称)。这只是忽略传递的任何其他参数。
C
Community

如果您想检查参数是否存在,您可以检查参数的 # 是否大于或等于您的目标参数编号。

以下脚本演示了它是如何工作的

测试.sh

#!/usr/bin/env bash

if [ $# -ge 3 ]
then
  echo script has at least 3 arguments
fi

产生以下输出

$ ./test.sh
~
$ ./test.sh 1
~
$ ./test.sh 1 2
~
$ ./test.sh 1 2 3
script has at least 3 arguments
$ ./test.sh 1 2 3 4
script has at least 3 arguments

P
Peter Mortensen

提醒一下,Bash 中的数字测试运算符仅适用于整数(-eq-lt-ge 等)

我喜欢确保我的 $vars 是整数

var=$(( var + 0 ))

在我测试它们之前,只是为了防止“[:需要整数 arg”错误。


巧妙的技巧,但请注意:由于 bash 无法处理算术浮点数,此方法可能会导致语法错误并返回非零值,这将成为启用 errexit 的障碍。 var=$(printf "%.0f" "$var") 可以处理浮点数,但在给定字符串时会出现非零退出。如果您不介意 awk,我使用的这种方法似乎是执行整数的最可靠的方法:var=$(<<<"$var" awk '{printf "%.0f", $0}')。如果 var 未设置,则默认为“0”。如果 var 是浮点数,则四舍五入到最接近的整数。负值也可以使用。
S
Serge Stroobandt

更现代

#!/usr/bin/env bash

if [[ $# -gt 0 ]]
  then echo hi
  else echo no arguments
fi

为什么这更现代?
@AlJohri 以下是您问题的一些答案:stackoverflow.com/q/669452/2192488superuser.com/q/1533900/219226
A
AndrewD

一个班轮 bash 功能验证

myFunction() {

    : ${1?"forgot to supply an argument"}
    if [ "$1" -gt "-1" ]; then
        echo hi
    fi

}

添加函数名称和用法

myFunction() {

    : ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage:  ${FUNCNAME[0]} some_integer"}
    if [ "$1" -gt "-1" ]; then
        echo hi
    fi

}

添加验证以检查是否为整数

要添加额外的验证,例如检查传递的参数是否为整数,请修改验证一行以调用验证函数:

: ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage:  ${FUNCNAME[0]} some_integer"} && validateIntegers $1 || die "Must supply an integer!"

然后,构造一个验证函数来验证参数,成功时返回 0,失败时返回 1,失败时中止脚本的 die 函数

validateIntegers() {

    if ! [[ "$1" =~ ^[0-9]+$ ]]; then
        return 1 # failure
    fi
    return 0 #success

}

die() { echo "$*" 1>&2 ; exit 1; }

更简单 - 只需使用 set -u

set -u 确保在使用时设置每个引用的变量,因此只需设置它并忘记它

myFunction() {
    set -u
    if [ "$1" -gt "-1" ]; then
        echo hi
    fi

}

M
Matthew

就我而言(有 7 个参数),唯一可行的解决方案是检查最后一个参数是否存在:

if [[ "$7" == '' ]] ; then
  echo "error"
  exit
fi

这不是真的。 $7 是第 7 个参数(如果您计算 $0 是脚本名称,则为第 8 个),因此这不会检查最后一个参数是否存在,它会检查第 7 个参数是否存在。
我确实同意这不是问题的解决方案,也是对不同(并且可能是可以避免的)问题的次优解决方案。七个位置论据似乎很重。此外,没有退出状态的 exit 将返回 echo "error" 的退出状态,我希望它为零。推荐 shellcheckset -euo pipefail。我现在要停下来...
虽然不是一个独特的答案,但它类似于其他有几个赞成的答案。似乎作者可能不是以英语为母语的人,并且可能意味着在他们的 7 个论点的情况下,这是一个可行的解决方案。我已经编辑了答案以反映这一点。绝对应该考虑@JackWasey 的建议。