在 Bash 中循环目录

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15854559/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 23:33:20  来源:igfitidea点击:

Looping over directories in Bash

bash

提问by alexvas

I have a fundamental question about how bash works, and a related practical question.

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

Fundamental question: suppose I am in a directory that has three subdirectories: a, b, and c.

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

hen the code

代码

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

spits out:

吐出:

a b c
a b c
a b c

i.e, diralways stores a list of all of the files/directories in my cwd. My question is: why in the world would this be convenient? In my opinion it is far more useful and intuitive to have dirstore each element at a time, i.e I would want to have output

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

a
b
c

Also, as per one of the answers - it is wrong to use for dir in $(ls), but when I use for dir in $(ls -l)I get even more copies of a b c(more than there are directories/files in the cwd). Why is that?

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

My second question is practical: how do I loop over all the directories (not files!) in my cwdthat start with capital W? I started with

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

for dir in `ls -l W*`

but this fails because a) the reason in question 1 and b) because it doesn't exclude files. Suggestions appreciated.

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

回答by Adrian Frühwirth

Never ever parse the output of lslike this (Why you shouldn't parse the output of ls(1)).

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

Also, your syntax is wrong. You don't mean (), you mean $().

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

That being said, to loop over directories starting with W you would do (or use the findcommand instead, depending on your scenario):

话虽如此,要循环以 W 开头的目录,您会这样做(或使用该find命令,具体取决于您的情况):

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

As for the output you get from the evil ls-loop, it should not look like that. This is the expected output and demonstrates why you do not want to use ls in the first place:

至于你从邪恶的 ls-loop 得到的输出,它不应该是那样的。这是预期的输出,并说明了为什么您不想首先使用 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

回答by Jahid

This should work:

这应该有效:

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

To be recursive in subdirectories too, use globstar:

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

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

You can make @Adrian Frühwirths' method to be recursive to sub-directories by using globstartoo:

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

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

From Bash Manual:

来自 Bash 手册:

globstar

If set, the pattern ‘**' used in a filename expansion context will match all files and zero or more directories and subdirectories. If the pattern is followed by a ‘/', only directories and subdirectories match.

nullglob

If set, Bash allows filename patterns which match no files to expand to a null string, rather than themselves.

环球之星

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

空球

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

回答by user1587276

Well, you know what you are seeing is not what you are expecting. The output you are seeing is not from the echo command, but from the dir command.

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

Try the following:

请尝试以下操作:

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