繁体   English   中英

如何处理 shell 脚本 arguments 中的“--”?

[英]How to handle “--” in the shell script arguments?

这个问题有 3 个部分,每个部分都很简单,但结合在一起并不是微不足道的(至少对我来说):)

需要编写一个脚本,它的 arguments 应该是什么:

  1. 另一个命令的一个名称
  2. 几个arguments为指令
  3. 文件列表

例子:

./my_script head -100 a.txt b.txt ./xxx/*.txt
./my_script sed -n 's/xxx/aaa/' *.txt

等等。

由于某种原因在我的脚本中我需要区分

  • 命令是什么
  • 命令的 arguments 是什么
  • 文件是什么

所以可能最标准的方式写上面的例子是:

./my_script head -100 -- a.txt b.txt ./xxx/*.txt
./my_script sed -n 's/xxx/aaa/' -- *.txt

问题1:这里有更好的解决方案吗?

在 ./my_script 中处理(第一次尝试):

command="$1";shift
args=`echo $* | sed 's/--.*//'`
filenames=`echo $* | sed 's/.*--//'`

#... some additional processing ...

"$command" "$args" $filenames #execute the command with args and files

filenames包含spaces和/或“--”时,此解决方案将失败,例如
/some--path/to/more/白痴文件名.txt

问题2:如何正确获取$command$args$filenames以供以后执行?

Question3: - 如何实现下面的执行风格?

echo $filenames | $command $args #but want one filename = one line (like ls -1)

这里是不错的 shell 解决方案,还是需要使用例如 perl?

首先,听起来您正在尝试编写一个脚本,该脚本接受一个命令和一个文件名列表,并依次对每个文件名运行该命令。 这可以在 bash 中的一行中完成:

$ for file in a.txt b.txt ./xxx/*.txt;do head -100 "$file";done
$ for file in *.txt; do sed -n 's/xxx/aaa/' "$file";done

但是,也许我误解了您的意图,所以让我单独回答您的问题。

而不是使用“--”(已经有不同的含义),下面的语法对我来说更自然:

./my_script -c "head -100" a.txt b.txt ./xxx/*.txt
./my_script -c "sed -n 's/xxx/aaa/'" *.txt

要提取 bash 中的 arguments,请使用getopts

SCRIPT=$0

while getopts "c:" opt; do
    case $opt in
        c)
            command=$OPTARG
            ;;
    esac
done

shift $((OPTIND-1))

if [ -z "$command" ] || [ -z "$*" ]; then
    echo "Usage: $SCRIPT -c <command> file [file..]"
    exit
fi

如果您想为剩余的每个 arguments 运行一个命令,它看起来像这样:

for target in "$@";do
     eval $command \"$target\"
done

如果你想从 STDIN 读取文件名,它看起来更像这样:

while read target; do
     eval $command \"$target\"
done

$@变量,当被引用时将能够对参数进行分组,因为它们应该是:

for parameter in "$@"
do
    echo "The parameter is '$parameter'"
done

如果给出:

head -100 test this "File name" out

将打印

the parameter is 'head'
the parameter is '-100'
the parameter is 'test'
the parameter is 'this'
the parameter is 'File name'
the parameter is 'out'

现在,您所要做的就是解析循环。 您可以使用一些非常简单的规则:

  1. 第一个参数始终是文件名
  2. 以破折号开头的参数是参数
  3. “--”之后或者不以“-”开头的,rest都是文件名。

您可以使用以下方法检查参数中的第一个字符是否为破折号:

if [[ "x${parameter}" == "x${parameter#-}" ]]

如果您以前没有见过这种语法,那它就是一个左过滤器 #分隔变量名的两部分。 第一部分是变量名,第二部分是要截断的glob过滤器(不是正则表达式)。 在这种情况下,它是一个破折号。 只要这个陈述不正确,你就知道你有一个参数。 顺便说一句,在这种情况下可能需要也可能不需要x 当你运行一个测试并且你有一个带有破折号的字符串时,测试可能会将它误认为是测试的参数而不是值。

放在一起会是这样的:

parameterFlag=""
for parameter in "$@"     #Quotes are important!
do
    if [[ "x${parameter}" == "x${parameter#-}" ]]
    then
         parameterFlag="Tripped!"
    fi
    if [[ "x${parameter}" == "x--" ]]
    then
         print "Parameter \"$parameter\" ends the parameter list"
         parameterFlag="TRIPPED!"
    fi
    if [ -n $parameterFlag ]
    then
        print "\"$parameter\" is a file"
    else
        echo "The parameter \"$parameter\" is a parameter"
    fi
done

问题 1

我不这么认为,至少如果您需要对任意命令执行此操作。

问题 3

command=$1
shift
while [ $1 != '--' ]; do
    args="$args $1"
    shift
done
shift
while [ -n "$1" ]; do
    echo "$1"
    shift
done | $command $args

问题2

这与问题 3 有何不同?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM