在Bash中循环遍历目录

ale*_*vas 15 bash

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

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

母鸡的代码

for dir in $(ls)
do 
    echo $dir
done
Run Code Online (Sandbox Code Playgroud)

吐出:

a b c
a b c
a b c
Run Code Online (Sandbox Code Playgroud)

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

a
b
c
Run Code Online (Sandbox Code Playgroud)

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

我的第二个问题是实用的:如何在我cwd用大写字母W开头的所有目录(不是文件!)上循环?我开始了

for dir in `ls -l W*`
Run Code Online (Sandbox Code Playgroud)

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

Adr*_*rth 38

永远不要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
Run Code Online (Sandbox Code Playgroud)

至于你从邪恶的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
Run Code Online (Sandbox Code Playgroud)


Jah*_*hid 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
Run Code Online (Sandbox Code Playgroud)

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

shopt -s globstar nullglob
for dir in ./**/;do
    echo "$dir" # dir is directory only because of the / after **
done
Run Code Online (Sandbox Code Playgroud)

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

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

来自Bash手册:

globstar

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

了nullglob

如果设置,Bash允许不匹配任何文件的文件名模式扩展为空字符串,而不是自己.