0

我正在编写我的第一个 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.

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

4

2 回答 2

2

将函数定义移动到脚本的顶部(在 hash-bang 下方)。bash反对未定义(当时)调用validate_args. usage定义应该在定义之前validate_args

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

    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
于 2013-04-23T17:59:38.873 回答
1

调用时,函数与命令无法区分——因此您不要使用括号:

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

此外,正如嫌疑人在他的回答中指出的那样,必须在调用函数之前定义它们。您可以使用脚本看到这一点:

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:#!/bin/bash

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.
于 2013-04-23T18:01:28.937 回答