17

我有一个关于 bash 如何工作的基本问题,以及一个相关的实际问题。

基本问题:假设我在一个包含三个子目录的目录中:a、b 和 c。

代码

for dir in $(ls)
do 
    echo $dir
done

吐出:

a b c
a b c
a b c

即,dir始终将所有文件/目录的列表存储在我的cwd. 我的问题是:为什么这会很方便?在我看来,一次存储每个元素更加有用和直观dir,即我想要输出

a
b
c

此外,根据答案之一 - 使用是错误的for dir in $(ls),但是当我使用时,for dir in $(ls -l)我会得到更多的副本a b c(超过 cwd 中的目录/文件)。这是为什么?

我的第二个问题很实用:我如何遍历所有cwd以大写 W 开头的目录(不是文件!)?我从

for dir in `ls -l W*`

但这失败了,因为a)问题1和b)的原因是因为它不排除文件。建议表示赞赏。

4

3 回答 3

44

永远不要解析这样的输出ls为什么你不应该解析 ls(1) 的输出)。

另外,您的语法错误。你不是说(),你是说$()

话虽这么说,要遍历以 W 开头的目录,您将执行(或使用find命令,具体取决于您的方案):

for path in /my/path/W*; do
    [ -d "${path}" ] || continue # if not a directory, skip
    dirname="$(basename "${path}")"
    do_stuff
done

至于你从邪恶的 ls 循环中得到的输出,它不应该是那样的。这是预期的输出,并说明了为什么您不想首先使用 ls :

$ find
.
./c
./a
./foo bar
./b

$ type ls
ls is hashed (/bin/ls)

$ for x in $(ls); do echo "${x}"; done
a
b
c
foo
bar
于 2013-04-06T18:40:36.937 回答
12

这应该有效:

shopt -s nullglob   # empty directory will return empty list
for dir in ./*/;do
    echo "$dir"         # dir is directory only because of the / after *
done

要在子目录中递归,请使用globstar

shopt -s globstar nullglob
for dir in ./**/;do
    echo "$dir" # dir is directory only because of the / after **
done

您也可以使用以下方法使@Adrian Frühwirths 的方法递归到子目录globstar

shopt -s globstar
for dir in ./**;do
    [[ ! -d $dir ]] && continue # if not directory then skip
    echo "$dir"
done

来自 Bash 手册:

全球星

如果设置,文件名扩展上下文中使用的模式 '**' 将匹配所有文件以及零个或多个目录和子目录。如果模式后跟“/”,则只有目录和子目录匹配。

空球

如果设置,Bash 允许不匹配文件的文件名模式扩展为空字符串,而不是它们本身。

于 2015-07-09T02:30:59.320 回答
0

好吧,你知道你所看到的不是你所期望的。您看到的输出不是来自 echo 命令,而是来自 dir 命令。

尝试以下操作:

ls -1 | while read line; do 

   if [-d "$line" ] ; then 
      echo $line
   fi

done


for files in $(ls) ; do

   if [-d "$files" ] ; then 
      echo $files
   fi

done
于 2013-04-06T20:38:21.670 回答