Bash脚本函数调用错误

时间:2013-04-23 17:54:43

标签: linux bash shell

我正在编写我的第一个Bash脚本,并且遇到函数调用的语法问题。

具体来说,我想调用我的脚本:

sh myscript.sh -d=<abc>

其中<abc>是固定父目录(~/app/dropzone)内特定目录的名称。如果子<abc>目录不存在,我希望脚本在转到该目录之前创建它。如果用户根本没有使用-d参数调用脚本,我希望脚本存在一个简单的用法消息。到目前为止,这是我对该剧本的最佳尝试:

#!/bin/bash
dropzone="~/app/dropzone"

# If the directory the script user specified exists, overwrite dropzone value with full path
# to directory. If the directory doesn't exist, first create it. If user failed to specify
# -d=<someDirName>, exit the script with a usage statement.
validate_args() {
    args=$(getopt d: "$*")
    set -- $args
    dir=$2
    if [ "$dir" ]
    then
        if [ ! -d "${dropzone}/targets/$dir" ]
        then
            mkdir ${dropzone}/targets/$dir
        fi
        dropzone=${dropzone}/targets/$dir
    else
        usage
    fi
}

usage() {
    echo "Usage: $0" >&2
    exit 1
}

# Validate script arguments.
validate_args $1

# Go to the dropzone directory.
cd dropzone
echo "Arrived at dropzone $dropzone."

# The script will now do other stuff, now that we're in the "dropzone".
# ...etc.

当我尝试运行时,我收到以下错误:

myUser@myMachine:~/app/scripts$ sh myscript.sh -dyoyo
mkdir: cannot create directory `/home/myUser/app/dropzone/targets/yoyo': No such file or directory
myscript.sh: 33: cd: can't cd to dropzone
Arrived at dropzone /home/myUser/app/dropzone/targets/yoyo.

我哪里出错了,我的一般方法是否正确?提前谢谢!

2 个答案:

答案 0 :(得分:3)

将函数定义移动到脚本的顶部(在hash-bang下面)。 bash反对未定义(此时)调用validate_argsusage定义应位于validate_args的定义之前。

if tests“[”和“]”中也应该有间距。

    if [ -d "$dropzone/targets/$1" ]

选项d的getopt测试应为 - :

    if [ "$(getopt d "$1")" ]

这是适用于我的validate_args版本。 我还必须更改我的shell上的放置区域〜不会在mkdir命令中扩展。

dropzone="/home/suspectus/app/dropzone"

validate_args() {
    args=$(getopt d: "$*")
    set -- $args
    dir=$2
    if [ "$dir" ]
    then
        if [ ! -d "${dropzone}/targets/$dir" ]
        then
            mkdir ${dropzone}/targets/$dir
        fi
        dropzone=${dropzone}/targets/$dir
    else
        usage
    fi
}

要传入所有参数,请使用$ *作为参数 - :

  validate_args $*

最后调用这样的脚本让getopt正确解析 - :

  myscript.sh -d dir_name

答案 1 :(得分:1)

调用时,函数与命令无法区分 - 所以你不要使用括号:

validate_args($1)  # Wrong
validate_args $1   # Right

此外,正如suspectusanswer指出的那样,必须在调用函数之前定义函数。你可以用脚本看到这个:

usage

usage()
{
    echo "Usage: $0" >&2
    exit 1
}
假设您没有名为usage: command not found的命令或函数,

将报告usage。在函数定义之后放置调用,它将正常工作。


您选择的界面不是命令的标准Unix调用约定。你通常使用:

dropzone -d subdir

而不是

dropzone -d=subdir

但是,我们可以处理您选择的接口(但不使用getopts,内置命令解释器,也许不使用GNU getopt,当然也不使用getopt你试过这样做)。这是支持-d=subdir的可行代码:     #!/斌/庆典

dropzone="$HOME/app/dropzone/targets"

validate_args()
{
    case "$1" in
    (-d=*)  dropzone="$dropzone/${1#-d=}"; mkdir -p $dropzone;;
    (*)     usage;;
    esac
}

usage()
{
    echo "Usage: $0 -d=dropzone" >&2
    exit 1
}

# Validate script arguments.
validate_args $1

# Go to the dropzone directory.
cd $dropzone || exit 1
echo "Arrived at dropzone $dropzone."

# The script will now do other stuff, now that we're in the "dropzone".
# ...etc.

请注意cd $dropzone || exit 1的谨慎做法;如果cd失败,你肯定不想继续在错误的目录中。

使用getopts内置命令解释器:

#!/bin/bash

dropzone="$HOME/app/dropzone/targets"

usage()
{
    echo "Usage: $0 -d dropzone" >&2
    exit 1
}

while getopts d: opt
do
    case "$opt" in
    (d) dropzone="$dropzone/$OPTARG"; mkdir -p $dropzone;;
    (*) usage;;
    esac
done
shift $(($OPTIND - 1))

# Go to the dropzone directory.
cd $dropzone || exit 1
echo "Arrived at dropzone $dropzone."

# The script will now do other stuff, now that we're in the "dropzone".
# ...etc.