我有一个名为“teleport.sh”的 shell 脚本,如下所示:
if [ $1="1" ];
then
shift
mv "$@" ~/lab/Sun
elif [ $1="2" ];
then
shift
mv "$@" ~/lab/Moon
elif [ $1="3" ];
then
shift
mv "$@" ~/lab/Earth
fi
Run Code Online (Sandbox Code Playgroud)
当我执行:
sh teleport.sh 2 testfile
Run Code Online (Sandbox Code Playgroud)
这testfile
被移动到~/lab/Sun
目录中,这让我很困惑,因为我没有将 1 或 '1' 传递给该脚本。
这里有什么问题?
Kar*_*rlo 19
使用空格可以解决您的问题。
if [ "$1" = 1 ];
then
shift
mv "$@" ~/lab/Sun
elif [ "$1" = 2 ];
then
shift
mv "$@" ~/lab/Moon
elif [ "$1" = 3 ];
then
shift
mv "$@" ~/lab/Earth
fi
Run Code Online (Sandbox Code Playgroud)
虽然这更整洁:
#!/bin/bash
action=$1
shift
files=("$@")
case $action in
1) mv -- "${files[@]}" ~/lab/Sun ;;
2) mv -- "${files[@]}" ~/lab/Moon ;;
3) mv -- "${files[@]}" ~/lab/Earth ;;
esac
Run Code Online (Sandbox Code Playgroud)
kon*_*box 11
首先显而易见的是,您应该在[
,test
或的参数之间提供空格[[
:
if [ "$1" = 1 ];
Run Code Online (Sandbox Code Playgroud)
在 Bash 中,[[ ]]
建议使用 using ,因为它不会为条件表达式做不必要的事情,例如分词和路径名扩展。也不需要引用双引号。==
还可以使用更易读的运算符。
if [[ $1 == 1 ]];
Run Code Online (Sandbox Code Playgroud)
补充说明:如果第二操作数还包含变量,报价是必要的,因为它可能会受到图案匹配,如果它包含可识别的字符,例如*
,?
,[]
等。如果扩展通配符或模式匹配与启用shopt -s extglob
,其它形式的喜欢@()
,!()
等也将被识别为模式。请参阅模式匹配。
对于像<
and>
这样的运算符,它可能仍然是必要的,因为我曾经遇到过不引用第二个参数会导致不同结果的错误。
至于第一个操作数,什么都不适用。
还要考虑这个更简单的变体:
case "$1" in
1)
mv -- "${@:2}" ~/lab/Sun
;;
2)
mv -- "${@:2}" ~/lab/Moon
;;
3)
mv -- "${@:2}" ~/lab/Earth
;;
esac
Run Code Online (Sandbox Code Playgroud)
或浓缩:
case "$1" in
1) mv -- "${@:2}" ~/lab/Sun ;;
2) mv -- "${@:2}" ~/lab/Moon ;;
3) mv -- "${@:2}" ~/lab/Earth ;;
esac
Run Code Online (Sandbox Code Playgroud)
"${@:2}"
是子串扩展或数组成员扩展的一种形式,其中2
是偏移量。这使得扩展从第二个值开始。有了这个,我们可能不需要使用shift
.
添加的--
防止mv
将以破折号 ( -
)开头的文件名识别为无效选项。
要回答为什么会发生的问题,这种行为[
也称为test
是在POSIX文件:
在下面的列表中,$1、$2、$3 和 $4 代表提交给测试的参数:
[...]
1 论点:
如果 $1 不为空,则退出真 (0);否则,退出假。
你传递给它 1 个参数,2=1
,它不为空,因此test
成功退出。
正如其他帖子(和shellcheck)指出的那样,如果您想比较相等性,则必须传递 3 个参数2
,=
和1
。