How to iterate over arguments in a Bash script
我有一个复杂的命令,我想制作一个shell/bash脚本。我可以很容易地用
1 | foo $1 args -o $1.ext |
我希望能够向脚本传递多个输入名称。正确的方法是什么?
当然,我想处理文件名中包含空格。
使用
1 2 3 4 | for var in"$@" do echo"$var" done |
这将迭代每个参数,并在单独的行上打印出来。$@的行为与$*类似,但在引用时,如果参数中有空格,则这些参数将被正确地分解:
1 2 3 4 | sh test.sh 1 2 '3 4' 1 2 3 4 |
重写VONC现在删除的答案。好的。
罗伯特·甘布尔简洁的回答直接涉及到这个问题。这篇文章进一步阐述了文件名中包含空格的一些问题。好的。
另请参见:$1:+"$@"in/bin/sh好的。
基础理论:
那么,
第二篇论文:如果你需要用空格来处理参数,然后将它们传递给其他命令,然后您有时需要非标准的辅助工具。(或者您应该小心地使用数组:
例子:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | $ mkdir"my dir" anotherdir $ ls anotherdir my dir $ cp /dev/null"my dir/my file" $ cp /dev/null"anotherdir/myfile" $ ls -Fltr total 0 drwxr-xr-x 3 jleffler staff 102 Nov 1 14:55 my dir/ drwxr-xr-x 3 jleffler staff 102 Nov 1 14:55 anotherdir/ $ ls -Fltr * my dir: total 0 -rw-r--r-- 1 jleffler staff 0 Nov 1 14:55 my file anotherdir: total 0 -rw-r--r-- 1 jleffler staff 0 Nov 1 14:55 myfile $ ls -Fltr"./my dir""./anotherdir" ./my dir: total 0 -rw-r--r-- 1 jleffler staff 0 Nov 1 14:55 my file ./anotherdir: total 0 -rw-r--r-- 1 jleffler staff 0 Nov 1 14:55 myfile $ var='"./my dir""./anotherdir"' && echo $var "./my dir""./anotherdir" $ ls -Fltr $var ls:"./anotherdir": No such file or directory ls:"./my: No such file or directory ls: dir": No such file or directory $ |
为什么不行?它不起作用,因为shell在展开前处理引号变量。因此,为了让壳牌公司注意嵌入在
1 2 3 4 5 6 7 8 9 | $ eval ls -Fltr $var ./my dir: total 0 -rw-r--r-- 1 jleffler staff 0 Nov 1 14:55 my file ./anotherdir: total 0 -rw-r--r-- 1 jleffler staff 0 Nov 1 14:55 myfile $ |
当您有诸如"EDOCX1"〔23〕之类的文件名(带引号、双引号和空格)时,这会变得非常棘手。好的。
1 2 3 4 5 6 7 8 9 | $ cp /dev/null"He said, "Don't do this!"" $ ls He said,"Don't do this!" anotherdir my dir $ ls -l total 0 -rw-r--r-- 1 jleffler staff 0 Nov 1 15:54 He said,"Don't do this!" drwxr-xr-x 3 jleffler staff 102 Nov 1 14:55 anotherdir drwxr-xr-x 3 jleffler staff 102 Nov 1 14:55 my dir $ |
贝壳(所有的)并不特别容易处理一些东西,所以(有趣的是)许多Unix程序不能很好地完成处理它们。在UNIX上,文件名(单个组件)可以包含除Slash和Nul
处理可能包含空格和其他麻烦的人物,你必须非常小心,我发现很久以前,我需要一个在Unix上不是标准的程序。我把它叫做
下面是一个使用中的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | : "@(#)$Id: delget.sh,v 1.8 1992/12/29 10:46:21 jl Exp $" # # Delta and get files # Uses escape to allow for all weird combinations of quotes in arguments case `basename $0 .sh` in deledit) eflag="-e";; esac sflag="-s" for arg in"$@" do case"$arg" in -r*) gargs="$gargs `escape "$arg"`" dargs="$dargs `escape "$arg"`" ;; -e) gargs="$gargs `escape "$arg"`" sflag="" eflag="" ;; -*) dargs="$dargs `escape "$arg"`" ;; *) gargs="$gargs `escape "$arg"`" dargs="$dargs `escape "$arg"`" ;; esac done eval delta"$dargs" && eval get $eflag $sflag"$gargs" |
(这几天我可能不会很彻底地使用"逃跑"这个词了——是的。例如,不需要使用
1 2 3 4 5 6 7 | $ escape $var '"./my' 'dir"' '"./anotherdir"' $ escape"$var" '"./my dir""./anotherdir"' $ escape x y z x y z $ |
我还有一个叫做
1 2 3 4 5 6 7 8 9 | $ echo"$var" "./my dir""./anotherdir" $ al $var "./my dir" "./anotherdir" $ al"$var" "./my dir""./anotherdir" $ |
[补充:为了说明不同的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | $ cat xx.sh set -x al $@ al $* al"$*" al"$@" $ sh xx.sh * */* + al He said, '"Don'\''t' do 'this!"' anotherdir my dir xx.sh anotherdir/myfile my dir/my file He said, "Don't do this!" anotherdir my dir xx.sh anotherdir/myfile my dir/my file + al He said, '"Don'\''t' do 'this!"' anotherdir my dir xx.sh anotherdir/myfile my dir/my file He said, "Don't do this!" anotherdir my dir xx.sh anotherdir/myfile my dir/my file + al 'He said,"Don'\''t do this!" anotherdir my dir xx.sh anotherdir/myfile my dir/my file' He said,"Don't do this!" anotherdir my dir xx.sh anotherdir/myfile my dir/my file + al 'He said,"Don'\''t do this!"' anotherdir 'my dir' xx.sh anotherdir/myfile 'my dir/my file' He said,"Don't do this!" anotherdir my dir xx.sh anotherdir/myfile my dir/my file $ |
注意,命令行上的
1 | set -- -new -opt and"arg with space" |
这设置了4个选项:"
嗯,这是一个相当长的答案-也许释义是更好的术语。根据要求提供
1 2 3 4 5 6 7 | #include <stdio.h> int main(int argc, char **argv) { while (*++argv != 0) puts(*argv); return(0); } |
这就是全部。它相当于Robert Gamble所展示的
还要注意,您可以将
1 2 | [ $# != 0 ] && printf"%s ""$@" |
需要条件,以便在不传递参数时不生成输出。
请注意,罗伯特的回答是正确的,它在
1 | for i in"$@" |
相当于:
1 | for i |
也就是说,你什么都不需要!
测试(
1 2 3 4 5 6 7 8 9 10 11 | $ set a b"spaces here" d $ for i; do echo"$i"; done a b spaces here d $ for i in"$@"; do echo"$i"; done a b spaces here d |
我第一次在Unix编程环境中读到这篇文章,作者是Kernighan和Pike。
在
for NAME [in WORDS ... ;] do COMMANDS; done If
'in WORDS ...;' is not present, then'in"$@"' is assumed.
对于简单的情况,也可以使用
1 2 3 4 5 6 | #this prints all arguments while test $# -gt 0 do echo $1 shift done |
您还可以作为数组元素访问它们,例如,如果您不想遍历所有这些元素
1 2 3 4 5 6 | argc=$# argv=($@) for (( j=0; j<argc; j++ )); do echo ${argv[j]} done |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | aparse() { while [[ $# > 0 ]] ; do case"$1" in --arg1) varg1=${2} shift ;; --arg2) varg2=true ;; esac shift done } aparse"$@" |