如何在Linux中循环目录?

Eri*_*pir 147 linux bash

我在Linux上用bash编写脚本,需要遍历给定目录中的所有子目录名称.如何遍历这些目录(并跳过常规文件)?

例如:
给定目录是否/tmp/
具有以下子目录:/tmp/A, /tmp/B, /tmp/C

我想要检索A,B,C.

gho*_*g74 412

到目前为止所有答案都使用find,所以这里只有shell.在您的情况下无需外部工具:

for dir in /tmp/*/     # list directories in the form "/tmp/dirname/"
do
    dir=${dir%*/}      # remove the trailing "/"
    echo ${dir##*/}    # print everything after the final "/"
done
Run Code Online (Sandbox Code Playgroud)

  • 如果它可以包含一个解释'dir = $ {dir%*/}`和`echo $ {dir ##*/}`正在做什么,那就太好了. (40认同)
  • 所以`for dir in*/; 回声$ dir; done`用于当前目录中的目录. (18认同)
  • +1 - 当你可以在通配符上添加斜杠时,为什么还要使用`find` (14认同)
  • 这是因为变量dir将在末尾包含反斜杠.他只是删除它以获得一个干净的名字.%将删除/的结尾.##将在开头删除/.这些是处理子串的运算符. (8认同)
  • 如果没有匹配,循环将用`/ tmp/*/`触发,最好包括检查目录是否确实存在. (8认同)
  • 嗯,是的,"发现"是*NIX机器上的瑞士军刀,可以找到与文件相关的东西.但是只有内置bash的纯版本也很有用.+1 (4认同)
  • 请注意:如果指定路径中没有目录,则将列出该路径中的所有文件,从而导致不良行为。使用“find”的解决方案更可靠。 (3认同)
  • 对于这个答案,也许使用 `echo \`basename $dir\` 会更清楚。 (2认同)

Bol*_*wyn 121

cd /tmp
find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n'
Run Code Online (Sandbox Code Playgroud)

一个简短的解释:find找到文件(非常明显)

  • .是目前的目录,在cd之后/tmp(恕我直言,这比/tmp直接在find命令中更灵活.你只有一个地方cd,如果你想要在这个文件夹中发生更多动作,则更改)

  • -maxdepth 1并且-mindepth 1确保,find实际上,只查看当前目录并且不包括.结果中的' '

  • -type d 只查找目录

  • -printf '%f\n 每次点击仅打印找到的文件夹名称(加上换行符).

瞧!


rub*_*o77 39

你可以循环遍历所有目录,包括隐藏的directrories(以点开头):

for file in */ .*/ ; do echo "$file is a directory"; done
Run Code Online (Sandbox Code Playgroud)

注意:仅当文件夹中至少存在一个隐藏目录时,才使用列表*/ .*/在zsh 中工作.在bash中它也将显示...


bash包含隐藏目录的另一种可能性是使用:

shopt -s dotglob;
for file in */ ; do echo "$file is a directory"; done
Run Code Online (Sandbox Code Playgroud)

如果要排除符号链接:

for file in */ ; do 
  if [[ -d "$file" && ! -L "$file" ]]; then
    echo "$file is a directory"; 
  fi; 
done
Run Code Online (Sandbox Code Playgroud)

要在每个解决方案中仅输出尾随目录名称(A,B,C作为疑问),请在循环中使用此名称:

file="${file%/}"     # strip trailing slash
file="${file##*/}"   # strip path and leading slash
echo "$file is the directoryname without slashes"
Run Code Online (Sandbox Code Playgroud)

示例(这也适用于包含空格的目录):

mkdir /tmp/A /tmp/B /tmp/C "/tmp/ dir with spaces"
for file in /tmp/*/ ; do file="${file%/}"; echo "${file##*/}"; done
Run Code Online (Sandbox Code Playgroud)


zpo*_*pon 16

使用包含空格的目录

Sorpigal的启发

while IFS= read -d $'\0' -r file ; do 
    echo $file; ls $file ; 
done < <(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d -print0)
Run Code Online (Sandbox Code Playgroud)

原帖(不适用于空格)

灵感来自Boldewyn:带find命令的循环示例.

for D in $(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d) ; do
    echo $D ;
done
Run Code Online (Sandbox Code Playgroud)


Ign*_*ams 7

find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n"
Run Code Online (Sandbox Code Playgroud)


Mat*_*ang 6

我经常使用的技术是find | xargs.例如,如果要使此目录中的每个文件及其所有子目录都具有全局可读性,则可以执行以下操作:

find . -type f -print0 | xargs -0 chmod go+r
find . -type d -print0 | xargs -0 chmod go+rx
Run Code Online (Sandbox Code Playgroud)

-print0选项以NULL字符而不是空格终止.该-0选项以相同的方式拆分其输入.所以这是用于带空格的文件的组合.

您可以将此命令链描绘为将每行输出find并将其粘贴在chmod命令的末尾.

如果要在中间而不是在结尾处运行作为其参数的命令,则必须有点创造性.例如,我需要更改到每个子目录并运行命令latemk -c.所以我用过(来自维基百科):

find . -type d -depth 1 -print0 | \
    xargs -0 sh -c 'for dir; do pushd "$dir" && latexmk -c && popd; done' fnord
Run Code Online (Sandbox Code Playgroud)

这具有效果for dir $(subdirs); do stuff; done,但对于名称中包含空格的目录是安全的.另外,单独的调用stuff是在同一个shell中进行的,这就是为什么在我的命令中我们必须返回到当前目录popd.


dex*_*tas 5

如果要在 for 循环中执行多个命令,可以将findwith mapfile(bash >= 4) 的结果保存为变量,并使用 遍历数组${dirlist[@]}。它还适用于包含空格的目录。

find命令基于Boldewyn 的回答。有关该命令的更多信息find可以在那里找到。

IFS=""
mapfile -t dirlist < <( find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n' )
for dir in ${dirlist[@]}; do
    echo ">${dir}<"
    # more commands can go here ...
done
Run Code Online (Sandbox Code Playgroud)


Lui*_*ire 5

长话短说:

(cd /tmp; for d in */; do echo "${d%/}"; done)
Run Code Online (Sandbox Code Playgroud)

解释。

无需使用外部程序。您需要的是 shell 通配模式。为了避免/tmp事后删除,我在子 shell 中运行它,这可能适合也可能不适合您的目的。

简而言之,Shell 通配符模式:

  • *匹配任何非空字符串任意次。
  • ?精确匹配一个字符。
  • [...]与括号之间的字符匹配。您还可以指定范围([a-z][A-F0-9]等)或类([:digit:][:alpha:]等)。
  • [^...]匹配不在大括号之间的字符之一。

* 如果没有文件名与模式匹配,shell 将返回模式不变。任何不属于上述字符或字符串的字符或字符串均代表其自身。


因此,该模式*/将匹配任何以/. /文件名中的尾部明确标识一个目录。

最后一位是删除尾部斜杠,这是通过变量替换实现的${var%PATTERN},它从 中包含的字符串末尾删除最短的匹配模式var,其中PATTERN是任何有效的通配模式。所以我们写${d%/},这意味着我们要从 表示的字符串中删除尾部斜杠d