遍历 $@ 的值
Iterating over the values of $@
我想遍历给 bash 脚本的参数,例如:
./bash_script file1 file2 file3
$@
为我提供了所有提供给脚本的文件,但我如何遍历这些文件?
我想 cat
每个文件并使用 awk
删除内容(我知道该怎么做,正是 $@
的解包让我感到困惑)。
诀窍是 双引号 它就像 "$@"
.
foo(){
printf ' ->%s\n' "$@";
}
foo "a b" c "d e"
相当于:
printf ' ->%s\n' "a b" c "d e"
如果上面的$@
是不是双引号,那么你会得到:
printf ' ->%s\n' a b c d e
由于 $IFS
个字符的分词($IFS
默认为 ' '$'\t'$'\n'
,即一个 space、一个制表符和一个换行符)
$@ 对比 $*
对于任何 array:
上的任何 @-expansion 双引号都是这样工作的
$ foo=( "a b" c "d e" )
$ printf ' ->%s\n' "${foo[@]}"
->a b
->c
->d e
相比之下,*-expansions(例如,$*
、${foo[*]}
)将使用 $IFS
的第一个字符加入将数组的项目合并为一个字符串:
$ foo=( "a b" c "d e" )
$ ( IFS=:; printf ' ->%s\n' "${foo[*]}" )
->a b:c:d e
如果不加引号,它将再次拆分这个 IFS 字符:
$ foo=( "a b" c "d e:f:g" )
$ ( IFS=:; printf ' ->%s\n' ${foo[*]} )
->a b
->c
->d e
->f
->g
在 for 循环中迭代 $@ 的技巧:
"$@"
数组比较特殊。如果你想在 for 循环中遍历 "$@"
,那么你可以缩写
for variable_name in "$@"; do
...
done
作为
for variable_name; do
done
因为跳过 for
循环的 in something
部分意味着 in "$@"
.
这甚至在 POSIX-only shells 中也有效(dash,bourne shell)没有数组变量但支持 "$@"
和 "$*
.
要遍历它们,您可以使用双引号 $@
,如下所示:
for arg in "$@" ; do
echo "--> ${arg}"
done
for arg in "$@"
也可以写成 for arg
(甚至 for arg in
),因为 bash
手册页指出:
for name [ [ in [ word ... ] ] ; ] do list ; done
blah blah blah
If the in word is omitted, the for command executes list once for each positional parameter that is set.
不过,我更喜欢显式变体。
以下文字记录显示了这一点:
pax: testprog.sh 1 2 3 '4 5' '' '6 7 8' "9"
--> 1
--> 2
--> 3
--> 4 5
-->
--> 6 7 8
--> 9
顺便说一句,您关于使用 cat
和 awk
修改文件的评论可能会平息“无用地使用 cat
奖励”人群的愤怒:-)
如果您正在考虑类似的事情:
cat "${fspec}" | awk 'do something'
那么cat
就完全没有必要了。您可以改用:
awk 'do something' "${fspec}"
我通常不担心 运行 额外流程的(小的)低效问题,但有些人会担心。
我想遍历给 bash 脚本的参数,例如:
./bash_script file1 file2 file3
$@
为我提供了所有提供给脚本的文件,但我如何遍历这些文件?
我想 cat
每个文件并使用 awk
删除内容(我知道该怎么做,正是 $@
的解包让我感到困惑)。
诀窍是 双引号 它就像 "$@"
.
foo(){
printf ' ->%s\n' "$@";
}
foo "a b" c "d e"
相当于:
printf ' ->%s\n' "a b" c "d e"
如果上面的$@
是不是双引号,那么你会得到:
printf ' ->%s\n' a b c d e
由于 $IFS
个字符的分词($IFS
默认为 ' '$'\t'$'\n'
,即一个 space、一个制表符和一个换行符)
$@ 对比 $*
对于任何 array:
上的任何 @-expansion 双引号都是这样工作的$ foo=( "a b" c "d e" )
$ printf ' ->%s\n' "${foo[@]}"
->a b
->c
->d e
相比之下,*-expansions(例如,$*
、${foo[*]}
)将使用 $IFS
的第一个字符加入将数组的项目合并为一个字符串:
$ foo=( "a b" c "d e" )
$ ( IFS=:; printf ' ->%s\n' "${foo[*]}" )
->a b:c:d e
如果不加引号,它将再次拆分这个 IFS 字符:
$ foo=( "a b" c "d e:f:g" )
$ ( IFS=:; printf ' ->%s\n' ${foo[*]} )
->a b
->c
->d e
->f
->g
在 for 循环中迭代 $@ 的技巧:
"$@"
数组比较特殊。如果你想在 for 循环中遍历 "$@"
,那么你可以缩写
for variable_name in "$@"; do
...
done
作为
for variable_name; do
done
因为跳过 for
循环的 in something
部分意味着 in "$@"
.
这甚至在 POSIX-only shells 中也有效(dash,bourne shell)没有数组变量但支持 "$@"
和 "$*
.
要遍历它们,您可以使用双引号 $@
,如下所示:
for arg in "$@" ; do
echo "--> ${arg}"
done
for arg in "$@"
也可以写成 for arg
(甚至 for arg in
),因为 bash
手册页指出:
for name [ [ in [ word ... ] ] ; ] do list ; done
blah blah blah
If the in word is omitted, the for command executes list once for each positional parameter that is set.
不过,我更喜欢显式变体。
以下文字记录显示了这一点:
pax: testprog.sh 1 2 3 '4 5' '' '6 7 8' "9"
--> 1
--> 2
--> 3
--> 4 5
-->
--> 6 7 8
--> 9
顺便说一句,您关于使用 cat
和 awk
修改文件的评论可能会平息“无用地使用 cat
奖励”人群的愤怒:-)
如果您正在考虑类似的事情:
cat "${fspec}" | awk 'do something'
那么cat
就完全没有必要了。您可以改用:
awk 'do something' "${fspec}"
我通常不担心 运行 额外流程的(小的)低效问题,但有些人会担心。