Bash 如何处理--&引用;在shell脚本参数中?
这个问题有三个部分,每个部分都很简单,但结合起来并不是一件小事(至少对我来说是这样):) 需要编写一个脚本,该脚本的参数应为:Bash 如何处理--&引用;在shell脚本参数中?,bash,shell,zsh,sh,Bash,Shell,Zsh,Sh,这个问题有三个部分,每个部分都很简单,但结合起来并不是一件小事(至少对我来说是这样):) 需要编写一个脚本,该脚本的参数应为: 另一个命令的一个名称 命令的几个参数 文件清单 示例: ./my_script head -100 a.txt b.txt ./xxx/*.txt ./my_script sed -n 's/xxx/aaa/' *.txt 等等 在我的脚本中,出于某种原因,我需要区分 命令是什么 命令的参数是什么 档案是什么 因此,编写上述示例的最标准方式可能是: ./my_sc
./my_script head -100 a.txt b.txt ./xxx/*.txt
./my_script sed -n 's/xxx/aaa/' *.txt
等等
在我的脚本中,出于某种原因,我需要区分
- 命令是什么
- 命令的参数是什么
- 档案是什么
./my_script head -100 -- a.txt b.txt ./xxx/*.txt
./my_script sed -n 's/xxx/aaa/' -- *.txt
问题1:这里有更好的解决方案吗
在./my_脚本中处理(首次尝试):
当文件名
包含空格
和/或“--”时,此解决方案将失败,例如/一些--path/to/more/idiotic file name.txt 问题2:如何正确获取
$command
其$args
和$filenames
以供以后执行
echo $filenames | $command $args #but want one filename = one line (like ls -1)
问题3:-如何实现以下执行风格
echo $filenames | $command $args #but want one filename = one line (like ls -1)
这是一个很好的shell解决方案,还是需要使用例如perl?问题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有什么不同?首先,听起来您正在尝试编写一个脚本,该脚本接受一个命令和一个文件名列表,然后依次对每个文件名运行该命令。这可以在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 如果要为剩余的每个参数运行命令,它将如下所示:
for target in "$@";do
eval $command \"$target\"
done
while read target; do
eval $command \"$target\"
done
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
如果您想从STDIN读取文件名,它看起来更像这样:
for target in "$@";do
eval $command \"$target\"
done
while read target; do
eval $command \"$target\"
done
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
$@
变量在被引用时将能够按其应有的方式对参数进行分组:
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'
现在,您所要做的就是解析循环。您可以使用一些非常简单的规则:
if [[ "x${parameter}" == "x${parameter#-}" ]]
如果您以前没有见过这种语法,那么它是一个左过滤器。#
将变量名的两部分分开。第一部分是变量的名称,第二部分是要截断的glob过滤器(不是正则表达式)。在这种情况下,它是一个单破折号。只要这句话不是真的,你就知道你有一个参数。顺便说一句,在这种情况下,x
可能需要,也可能不需要。当您运行测试时,如果您有一个带破折号的字符串,测试可能会将其误认为是测试的参数,而不是值
把它放在一起会是这样的:
for target in "$@";do
eval $command \"$target\"
done
while read target; do
eval $command \"$target\"
done
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.为什么要用背部抽搐?它们已经被弃用了,除非您希望以root用户身份在Solaris或AIX上做大量工作,否则没有必要这样做。使用$(cmd)!2.(更多关于您的问题),请阅读getopt和getopts(用于shell)。我在这里看到了很多例子,至少有一个非常详细。再加上像
while($#>0))这样的东西做processArgs;转移;完成
将有所帮助。3.考虑使用case语句。对于--
您可能必须对其进行转义或引用,或将其转换为类似“[-][-]”的charclass。如果文件名包含空格,echo$filenames | sed-将中断。e、 g.echo“file1.txt”“file2 with spaces.txt”-因此询问-我的第一次尝试是错误的。@TomShaw:第一篇文章不错。对于最后一块代码,可能需要在循环内部加上eval
。感谢您做了大量的列表。;-)@谢:谢谢你的反馈!这一行filenames=$*
在本来是好代码的代码中是非常糟糕的。一般来说,不要使用$*
。特别是在这种情况下,不要使用$*
。如果使用Bash数组,则“$@”就可以了。实际上,循环最好写为“$@”中目标的;做完成
。如果文件名实际上不包含空格,那么$*
就可以了。只要名称中有空格,$*
就会处理错误。谢谢@Jonathan,我已经加入了你的修复程序x
破解只适用于古代贝壳。请不要使用它,它会让代码变得丑陋。@nyuszika7h,……好吧——在现代shell中也有一些角落的情况需要它,但这些情况只存在于[]
(而不是[[[]]
)中,并且当test
传递了三个以上的参数时(因此,当使用-a
或-o
时)。。。这就是为什么最新版本的POSIX将它们描述为不推荐使用的部分原因。