1

我在 Bash shell 脚本库中有一个函数,它使用 getopts 来接受参数。我想在这些参数之一中指定一个 Bash 命令。然后,该函数继续将此存储的命令用于一个目的或另一个目的(例如,以自动方式生成 GNOME 桌面启动器,并将此存储的命令指定为启动器的执行)。如何以用户友好的方式保留命令中的特殊字符(并且,我的意思是不要求用户转义指定命令中的特殊字符或执行其他异常困难的操作)?

因此,函数的开头可能具有以下特征:

OPTIND=1; while getopts ":i:o:" options; do
    case "${options}" in
        i)
            command_1="${OPTARG}"
            ;;
        o)
            fileName_1="${OPTARG}"
            ;;
        \?)
            echo "invalid option -"${OPTARG}""
            return
            ;;
        :)
            echo "option -"${OPTARG}" requires an argument"
            return
            ;;
    esac

作为函数参数给出的命令可能如下所示:

echo "hello" | festival --tts
4

2 回答 2

0

您可以将通用参数解析与 getopts 混合使用:

OPTIND=1
while :; do
    case "${!OPTIND}" in
    --tts)
        TTS=true
        (( ++OPTIND ))
        ;;
    --another-with-arg)
        (( ++OPTIND ))
        # Perhaps add a check as well if optarg is valid.
        ANOTHER=${!OPTIND}
        (( ++OPTIND ))
        ;;
    *)
        if getopts ":ai:o:" options; then
            case "${options}" in
            i)
                command_1="${OPTARG}"
                ;;
            o)
                fileName_1="${OPTARG}"
                ;;
            \?)
                echo "invalid option -"${OPTARG}""
                return
                ;;
            :)
                echo "option -"${OPTARG}" requires an argument"
                return
                ;;
            esac
        else
            return
        fi
        ;;
    esac
done

虽然如果我在那里,我根本不会使用 getopts

于 2013-09-25T17:05:35.843 回答
0

我的解释是,您希望用户能够编写如下内容:

my_script -i echo "hello" | festival --tts

并将 -i 之后的整个序列(包括管道字符)作为参数接受。

不幸的是,这真的是不可能的。被调用的脚本没有什么神奇之处,因为在调用脚本之前已经解析了整个命令行。

当然,用户可以写:

my_script -i 'echo "hello" | festival --tts'

但是,如果所需的命令行包含撇号,则需要付出巨大的努力。

“通常”的方法(例如,由find实用程序的-exec选项使用)是接受命令行参数,直到;找到 a。当然,;需要转义,就像任何管道或其他 shell 元字符一样。

您可以做的一件事是提供一个单独的选项,也许-I,它从中读取一行stdin并将其用作命令。这对于难以引用的复杂命令行来说会很方便,尽管如果该实用程序还想stdin用于其他目的,那就有点尴尬了。有了它,用户可以键入:

my_script -I file <<"EOF"
very_complicated_command 'with$x' "$all kinds of punctuation" 2> logfile | even_pipes
EOF
于 2013-09-25T17:42:10.217 回答