AIX 上的一个脚本,用于检查传递的参数数量并在参数不正确时发出警告:-
if [ "$#" -ge 1 ]; then
...
else
echo 'Usage: myscript <a> [b] [c]'
fi
该脚本设置了一些环境变量,以便获取它。我的意思是我在命令行上输入以下内容。没有第二个脚本,我不是从另一个脚本中获取脚本。
. ./myscript.sh
如果我不向它传递任何参数,我希望它打印出使用语句,但它会使用传递给所获取的上一个命令的参数来运行(甚至不一定是这个脚本!)。
为了仔细检查这一点,我在脚本的开头添加了这一行,以证明情况确实如此。
echo $# $@
如果我不传递任何参数,它会打印出先前来源脚本中的参数数量和列表。
当我向它传递零个参数并获取它时,如何让它说$#
为零?
最小的可能重新创建是一个脚本,因此:-
myscript.sh
echo $# $@
然后运行它:-
. ./myscript.sh a b c
打印出
3 a b c
然后在没有任何参数的情况下再次运行它:-
. ./myscript.sh
打印出相同的结果
3 a b c
当你期望它打印出来时
0
如果您不获取脚本并直接运行它:-
./myscript.sh
然后它按预期工作并打印出来
0
我希望这能澄清当前的问题。
由于我似乎得到了很多答案来解释为什么上述方法不起作用,并且没有答案告诉我应该做什么,所以我想我会再尝试一次尝试解释我想要做什么。
要求
我需要编写一个脚本,该脚本至少需要一个参数,如果未使用所述参数调用它,则会发出抱怨(请参阅上面问题中的第一段代码),并且该脚本需要设置一些环境变量。由于第二个要求,我假设我需要获取脚本,以便在脚本完成时仍然设置环境变量。如何编写一个脚本来判断何时没有传递参数,并且还可以设置环境变量?
答案1
在
. path/to/script at least one argument
正如其他人所说,根据 shell 的不同,这些额外的参数要么被忽略(Bourne、Almquist),要么替换当前的位置参数集($@
、$1
、$2
...)以解释该脚本(大多数其他 shell)。 POSIX 不指定将额外参数传递给 时的行为.
。在这种情况下,对于set a b
脚本中对位置参数(如 )所做的任何更改是否会在完成后保留,shell 之间也存在一些差异.
。
在:
. path/to/script
但是,行为是指定的。需要位置参数不是受到影响,所以对于脚本的解释将保持与之前相同。
如果您希望在解释该脚本期间位置参数为空列表,则需要事先重置它,或使用函数:
set -- # or shift "$#"
. path/to/script
(尽管位置参数丢失)。或者使用一个函数:
dot() { file=$1; shift; . "$file"; }
dot path/to/myscript
执行命令时.
,位置参数将是函数的位置参数。在 后面shift
,它将是传递给函数的参数减去第一个参数,因此在上面是一个空列表;但这意味着使用该函数,您可以将任意位置参数列表传递给源脚本,如下所示:
dot path/to/myscript extra args
这些将在源脚本中extra
args
提供。$1
$2
如果myscript
调用set
修改位置参数列表,则只会影响函数的位置参数,并且这些更改在函数返回后不会持续。
答案2
Bash 的帮助文本.
:
.: . filename [arguments]
Execute commands from a file in the current shell.
Read and execute commands from FILENAME in the current shell. The
entries in $PATH are used to find the directory containing FILENAME.
If any ARGUMENTS are supplied, they become the positional parameters
when FILENAME is executed.
注意这句话:“如果提供任何参数”。如果没有参数,则保留当前位置参数。
$ cat /tmp/sourceme.sh
printf "%d: " "$#"
printf "<%s> " "$@"
printf "\n"
$ bash -c 'set -- aa bb; . /tmp/sourceme.sh'
2: <aa> <bb>
$ bash -c 'set -- aa bb; . /tmp/sourceme.sh foo bar'
2: <foo> <bar>
我测试的所有其他 shell(zsh、ksh)的行为类似。除了dash
, 其中总是保留原始位置参数。
$ dash -c 'set -- aa bb; . /tmp/sourceme.sh foo bar'
2: <aa> <bb>
我在中看不到任何有关重置位置参数的提及POSIX 定义.
因此,似乎.
从一开始就给出论点是不标准的。
您可以使用函数来代替源脚本,因为它们可以接受标准 shell 中的参数。在这种情况下,您将获取一个定义该函数的文件。
define_fun.sh
例如,带有函数定义的文件 ( ):
#!/bin/sh
f() {
echo "args: $# $@" # just a test
if [ "$#" = 0 ]; then
echo please give at least one argument
return 1
fi;
ENVVAR=$1 # this should be visible to the whole shell
export ENVVAR # and any commands called later
}
然后使用它:
$ . define_fun.sh # source the file to load the func in the current shell
$ f # actually run it: this'll complain
$ f 123 456 # this should set ENVVAR
$ echo $ENVVAR # and this will print '123'
您可以将函数定义放在 shell 的初始化文件之一中(~/.profile
?取决于 shell。)
答案3
将参数传递给dot
内置命令是 Korn Shell 扩展,不允许在其他 shell 中使用。
由于 POSIX 标准没有提及 dot 命令的 $# 和 $@,因此当前 shell 的参数对 dot 命令是可见的,因此如果您将 shell 调用为:
myshell -s a b c
然后打电话
. ./myscript.sh
预计将打印
3 a b c