Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 在shell脚本参数上循环并将带引号的参数传递给函数_Bash_Shell_Terminal_Command Line Interface - Fatal编程技术网

Bash 在shell脚本参数上循环并将带引号的参数传递给函数

Bash 在shell脚本参数上循环并将带引号的参数传递给函数,bash,shell,terminal,command-line-interface,Bash,Shell,Terminal,Command Line Interface,我在下面有一个脚本,它从一个bash脚本目录中获取源代码,然后解析命令的标志以从源代码文件中运行特定函数 在脚本目录中指定此函数: function reggiEcho () { echo $1 } 下面是一些电流输出的例子 $ reggi --echo hello hello $ reggi --echo hello world hello $ reggi --echo "hello world" hello $ reggi --echo "hello" --echo "world" h

我在下面有一个脚本,它从一个bash脚本目录中获取源代码,然后解析命令的标志以从源代码文件中运行特定函数

脚本
目录中指定此函数:

function reggiEcho () {
  echo $1
}
下面是一些电流输出的例子

$ reggi --echo hello
hello
$ reggi --echo hello world
hello
$ reggi --echo "hello world"
hello
$ reggi --echo "hello" --echo "world"
hello
world
正如您所看到的,引用的参数不受尊重,因为它们应该是“helloworld”,应该正确地回显

这是脚本,问题在
while
循环中

如何解析这些标志,并保持将带引号的参数传递到函数中

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
STR="$(find $DIR/scripts -type f -name '*.sh' -print)"
ARR=( $STR )
TUSAGE="\n"

for f in "${ARR[@]}"; do
    if [ -f $f ]
    then
        . $f --source-only

        if [ -z "$USAGE" ]
        then
            :
        else
            TUSAGE="$TUSAGE \t$USAGE\n"
        fi

        USAGE=""
    else
        echo "$f not found"
    fi
done 

TUSAGE="$TUSAGE \t--help (shows this help output)\n"

function usage() {
  echo "Usage: --function <args> [--function <args>]"
  echo $TUSAGE
  exit 1
}

HELP=false

cmd=()
while [ $# -gt 0 ]; do                         # loop until no args left

    if [[ $1 = '--help' ]] || [[ $1 = '-h' ]] || [[ $1 = '--h' ]] || [[ $1 = '-help' ]]; then
        HELP=true
    fi

    if [[ $1 = --* ]] || [[ $1 = -* ]]; then                    # arg starts with --
        if [[ ${#cmd[@]} -gt 0 ]]; then
            "${cmd[@]}"
        fi
        top=`echo $1 | tr -d -`                              # remove all flags
        top=`echo ${top:0:1} | tr  '[a-z]' '[A-Z]'`${top:1}  # make sure first letter is uppercase
        top=reggi$top                                         # prepend reggi
        cmd=( "$top" )                                       # start new array
    else
        echo $1
        cmd+=( "$1" )
    fi
    shift
done

if [[ "$HELP" = true ]]; then
    usage
elif [[ ${#cmd[@]} -gt 0 ]]; then
    ${cmd[@]}
else
    usage
fi
DIR=“$(cd“$(dirname“${BASH_SOURCE[0]}”)”&&pwd)”
STR=“$(查找$DIR/scripts-type f-name'*.sh'-print)”
ARR=($STR)
TUSAGE=“\n”
对于“${ARR[@]}”中的f;做
如果[-f$f]
然后
. $f——仅限源
如果[-z“$USAGE”]
然后
:
其他的
TUSAGE=“$TUSAGE\t$USAGE\n”
fi
用法=“”
其他的
回显“$f未找到”
fi
完成
TUSAGE=“$TUSAGE\t--help(显示此帮助输出)\n”
函数用法(){
echo“用法:--function[--function]”
echo$TUSAGE
出口1
}
帮助=错误
cmd=()
而[$#-gt 0];循环,直到没有参数
如果[$1='--help'].[$1='-h'].[$1='--h'].[$1='-h'].[$1='-help']];然后
帮助=正确
fi
如果[[$1=-*]| |[[$1=-*]];然后#arg以--
如果[${cmd[@]}-gt 0]];然后
“${cmd[@]}”
fi
top=`echo$1 | tr-d-`#删除所有标志
top=`echo${top:0:1}| tr'[a-z]''[a-z]'`${top:1}#确保第一个字母是大写的
top=reggi$top#前置reggi
cmd=(“$top”)#启动新数组
其他的
回声1美元
cmd+=(“$1”)
fi
转移
完成
如果[[“$HELP”=true]];然后
使用
elif[${cmd[@]}-gt 0]];然后
${cmd[@]}
其他的
使用
fi

此脚本中有许多地方的变量引用没有双引号。这意味着变量的值将受到单词吐出和通配符扩展的影响,这可能会产生各种奇怪的效果

您看到的具体问题是由于最后一行的第四行,
${cmd[@]}
上有一个不带引号的变量引用。使用
cmd=(echo“hello world”)
,分词使其等同于
echo hello world
,而不是
echo“hello world”

修复这一行将修复当前的问题,但还有许多其他未引用的变量引用可能会在以后导致其他问题。我建议把它们都修好。Cyrus的推荐很善于指出这些问题,同时也会注意到一些我在这里不涉及的其他问题。这里没有提到的一点是,您应该避免使用所有caps变量名(
DIR
TUSAGE
,等等)——有一堆具有特殊含义的所有caps变量,很容易意外地重用其中一个,并产生奇怪的效果。小写和混合大小写变量更安全

我还建议不要在字符串中使用
\t
\n
,并分别使用
echo
将它们转换为制表符和换行符。有些版本的
echo
会自动执行此操作,有些版本需要
-e
选项来告诉他们执行此操作,有些版本会打印“-e”作为其输出的一部分。。。一团糟。在bash中,您可以使用
$'…'
直接转换这些转义序列,例如:

tusage="$tusage"$' \t--help (shows this help output)\n'    # Note mixed quoting modes
echo "$tusage"    # Note that double-quoting is *required* for this to work right
您还应该修复文件列表,使其不依赖于未引用(请参阅chepner的评论)。如果不需要扫描$DIR/scripts的子目录,可以使用一个简单的通配符(注意小写变量,并且该变量是双引号,但通配符不是):

如果您需要查看子目录,它会更复杂。如果您有bash v4,则可以使用globstar通配符,如下所示:

shopt -s globstar
arr=( "$dir/scripts"/**/*.sh )
如果您的脚本可能必须在bash v3下运行,请参阅,或仅使用以下命令:

while IFS= read -r -d '' f <&3; do
    if [ -f $f ]
        # ... etc
done 3< <(find "$dir/scripts" -type f -name '*.sh' -print0)

而IFS=read-r-d''f如果你能像在
ARR=($STR)
中那样安全地填充一个数组,那么你一开始就不需要数组。第一个
ARR=($STR)
只是为了分割文件以便我能找到它们的来源,这不是参数解析部分。这仍然是错误的,如果它与你实际问的问题无关,它就不属于问题。添加一个shebang,然后将脚本粘贴到那里:你用
shell
标记了这个问题。请注意,posix shell没有数组。
while IFS= read -r -d '' f <&3; do
    if [ -f $f ]
        # ... etc
done 3< <(find "$dir/scripts" -type f -name '*.sh' -print0)