2011-05-01 59 views
7

在循环这样的变量时出现问题。我准备了两个例子来展示这个问题。

EX1:

#!/bin/bash 
DIRS="[email protected]" 

for DIR in $DIRS; do 
    echo "$DIR" 
done 

EX2:

#!/bin/bash 
for DIR in "[email protected]"; do 
    echo "$DIR" 
done 

第二个例子的工作原理如预期(和所需的)。快速测试如下:

$ ex1 "a b" "c" 
a 
b 
c 
$ ex2 "a b" "c" 
a b 
c 

究其原因,我为什么要使用第一种方法是因为我希望能够到多个目录传递给程序或没有使用当前目录。像这样:

[ $# -eq 0 ] && DIRS=`pwd` || DIRS="[email protected]" 

那么,我如何得到例1是空间安全的?

回答

10

使用数组而不是简单变量。

declare -a DIRS 

DIRS=("[email protected]") 

for d in "${DIRS[@]}" 
do echo "$d" 
done 

这产生的结果:

$ bash xx.sh a "b c" "d e f g" h z 
a 
b c 
d e f g 
h 
z 
$ 
+0

Aaah,我尝试了很多,我非常接近。我只是忘了$ {DIRS [@]}的引号。谢谢 – Frank 2011-05-01 23:01:42

+0

@Frank:数组符号有点繁琐 - 每次使用它时都必须返回参考手册。我越来越好,但有多年Bourne shell经验可以覆盖。 – 2011-05-01 23:07:35

0

一种方法是,当你使用参数与别的参数内再次更换空间,然后代替空格:

dirs="${@/ /###}" 
for dir in $dirs; do 
    echo "${dir/###/ }" 
done 

这依赖于你能拿出一串字符你可以确信自己永远不会出现在真实的文件名中。

对于你有,你希望能够提供目录的显式列表或默认为当前目录之间进行选择的具体情况,更好的解决办法可能是使用的函数:

do_something() { 
    for dir in "[email protected]"; do 
     echo "$dir" 
    done 
} 

if [ $# -eq 0 ]; then 
    do_something . 
else 
    do_something "[email protected]" 
fi 

或可能:

do_something() { 
    echo "$1" 
} 

if [ $# -eq 0 ]; then 
    do_something . 
else 
    for dir in "[email protected]"; do 
     do_something "$dir" 
    done 
fi 
4

为什么不使用默认的扩展功能?

for DIR in "${@:-$(pwd)}"; do 
    echo $DIR 
done