如何在 Linux 中循环目录?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2107945/
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-08-03 19:42:13  来源:igfitidea点击:

How to loop over directories in Linux?

linuxbash

提问by Erik Sapir

I am writing a script in bash on Linux and need to go through all subdirectory names in a given directory. How can I loop through these directories (and skip regular files)?

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

For example:
the given directory is /tmp/
it has the following subdirectories: /tmp/A, /tmp/B, /tmp/C

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

I want to retrieve A, B, C.

我想检索 A、B、C。

采纳答案by Boldewyn

cd /tmp
find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n'

A short explanation:

一个简短的解释:

  • findfinds files (quite obviously)

  • .is the current directory, which after the cdis /tmp(IMHO this is more flexible than having /tmpdirectly in the findcommand. You have only one place, the cd, to change, if you want more actions to take place in this folder)

  • -maxdepth 1and -mindepth 1make sure that findonly looks in the current directory and doesn't include .itself in the result

  • -type dlooks only for directories

  • -printf '%f\nprints only the found folder's name (plus a newline) for each hit.

  • find查找文件(很明显)

  • .是当前目录,在cdis 之后/tmp(恕我直言,这比/tmp直接在find命令中更灵活。cd如果您希望在此文件夹中进行更多操作,您只有一个地方, 可以更改)

  • -maxdepth 1-mindepth 1确保find只在当前目录中查找而不将.自身包含在结果中

  • -type d只查找目录

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

Et voilà!

等等!

回答by Anonymous

find . -type d -maxdepth 1

find . -type d -maxdepth 1

回答by Ignacio Vazquez-Abrams

find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n"

回答by ghostdog74

All answers so far use find, so here's one with just the shell. No need for external tools in your case:

到目前为止所有答案都使用find,所以这里是一个只有外壳的答案。在您的情况下不需要外部工具:

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

回答by zpon

Works with directories which contains spaces

适用于包含空格的目录

Inspired by Sorpigal

灵感来自索皮加尔

while IFS= read -d $'
for D in $(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d) ; do
    echo $D ;
done
' -r file ; do echo $file; ls $file ; done < <(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d -print0)

Original post (Does not work with spaces)

原始帖子(不适用于空格)

Inspired by Boldewyn: Example of loop with findcommand.

Boldewyn 的启发:带find命令的循环示例。

for file in */ .*/ ; do echo "$file is a directory"; done

回答by rubo77

You can loop through all directories including hidden directrories (beginning with a dot) with:

您可以使用以下命令遍历所有目录,包括隐藏目录(以点开头):

shopt -s dotglob;
for file in */ ; do echo "$file is a directory"; done

note: using the list */ .*/works in zsh only if there exist at least one hidden directory in the folder. In bash it will show also .and ..

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



Another possibility for bash to include hidden directories would be to use:

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

for file in */ ; do 
  if [[ -d "$file" && ! -L "$file" ]]; then
    echo "$file is a directory"; 
  fi; 
done


If you want to exclude symlinks:

如果要排除符号链接:

file="${file%/}"     # strip trailing slash
file="${file##*/}"   # strip path and leading slash
echo "$file is the directoryname without slashes"


To output only the trailing directory name (A,B,C as questioned) in each solution use this within the loops:

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

mkdir /tmp/A /tmp/B /tmp/C "/tmp/ dir with spaces"
for file in /tmp/*/ ; do file="${file%/}"; echo "${file##*/}"; done

Example (this also works with directories which contains spaces):

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

find . -type f -print0 | xargs -0 chmod go+r
find . -type d -print0 | xargs -0 chmod go+rx

回答by Matthew Leingang

The technique I use most often is find | xargs. For example, if you want to make every file in this directory and all of its subdirectories world-readable, you can do:

我最常使用的技术是find | xargs. 例如,如果你想让这个目录中的每个文件及其所有子目录都可读,你可以这样做:

find . -type d -depth 1 -print0 | \
    xargs -0 sh -c 'for dir; do pushd "$dir" && latexmk -c && popd; done' fnord

The -print0option terminates with a NULL character instead of a space. The -0option splits its input the same way. So this is the combination to use on files with spaces.

-print0选项以 NULL 字符而不是空格结束。该-0选项以相同的方式拆分其输入。所以这是在带有空格的文件上使用的组合。

You can picture this chain of commands as taking every line output by findand sticking it on the end of a chmodcommand.

您可以将这一系列命令想象成获取每一行输出find并将其粘贴在chmod命令的末尾。

If the command you want to run as its argument in the middle instead of on the end, you have to be a bit creative. For instance, I needed to change into every subdirectory and run the command latemk -c. So I used (from Wikipedia):

如果您想在中间而不是最后运行命令作为其参数,则必须有点创意。例如,我需要切换到每个子目录并运行命令latemk -c. 所以我使用了(来自维基百科):

for dir in directory/*                                                     
do                                                                                 
  echo ${dir}                                                                  
done

This has the effect of for dir $(subdirs); do stuff; done, but is safe for directories with spaces in their names. Also, the separate calls to stuffare made in the same shell, which is why in my command we have to return back to the current directory with popd.

这具有for dir $(subdirs); do stuff; done, 但对于名称中带有空格的目录是安全的。此外,对 的单独调用stuff是在同一个 shell 中进行的,这就是为什么在我的命令中我们必须使用popd.

回答by Harry Moreno

a minimal bash loop you can build off of (based off ghostdog74 answer)

您可以构建的最小 bash 循环(基于 ghostdog74 答案)

for dir in directory/*
do
  zip -r ${dir##*/} ${dir}
done                                               

to zip a whole bunch of files by directory

按目录压缩一大堆文件

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

回答by dexteritas

If you want to execute multiple commands in a for loop, you can save the result of findwith mapfile(bash >= 4) as an variable and go through the array with ${dirlist[@]}. It also works with directories containing spaces.

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

The findcommand is based on the answerby Boldewyn. Further information about the findcommand can be found there.

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

##代码##