循环在Bash中的目录

时间:2013-04-06 18:34:18

标签: bash

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

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

hen the code

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中的文件)。那是为什么?

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

开始
for dir in `ls -l W*`

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

3 个答案:

答案 0 :(得分:37)

永远不要解析ls的输出(Why you shouldn't parse the output of 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

答案 1 :(得分:10)

这应该有效:

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

你也可以使用globstar使@AdrianFrühwirths方法递归到子目录:

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

From Bash Manual:

  

globstar

     

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

     

了nullglob

     

如果设置,Bash允许不匹配任何文件的文件名模式进行扩展   到一个空字符串,而不是自己。

答案 2 :(得分: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