简体   繁体   English

循环在Bash中的目录

[英]Looping over directories in Bash

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

ie, dir always stores a list of all of the files/directories in my cwd . 即, dir始终存储我的cwd中所有文件/目录的列表。 My question is: why in the world would this be convenient? 我的问题是:为什么世界会这么方便? In my opinion it is far more useful and intuitive to have dir store each element at a time, ie I would want to have output 在我看来,让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 abc (more than there are directories/files in the cwd). 另外,根据其中一个答案 - for dir in $(ls)使用for dir in $(ls)是错误的,但是当我for dir in $(ls -l)使用for dir in $(ls -l)我得到更多的abc副本(比目录/文件更多)在cwd)。 Why is that? 这是为什么?

My second question is practical: how do I loop over all the directories (not files!) in my cwd that start with capital W? 我的第二个问题是实用的:如何在我的cwd中以大写cwd W开头的所有目录(不是文件!)循环? I started with 我开始了

for dir in `ls -l W*`

but this fails because a) the reason in question 1 and b) because it doesn't exclude files. 但这失败了因为a)问题1和b)中的原因,因为它不排除文件。 Suggestions appreciated. 建议表示赞赏。

Never ever parse the output of ls like 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 find command 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. 至于你从邪恶的ls循环得到的输出,它应该看起来不那样。 This is the expected output and demonstrates why you do not want to use ls in the first place: 这是预期的输出,并说明了为什么你不想首先使用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

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 globstar too: 您可以@AdrianFrü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 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 了nullglob

If set, Bash allows filename patterns which match no files to expand to a null string, rather than themselves. 如果设置,Bash允许不匹配任何文件的文件名模式扩展为空字符串,而不是自己。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM