ChatGPT解决这个技术问题 Extra ChatGPT

在 Bash 中仅使用 ls 列出目录?

此命令列出当前路径中的目录:ls -d */

模式 */ 究竟做了什么?

我们如何在上述命令(例如 ls -d /home/alice/Documents)中给出绝对路径以仅列出该路径中的目录?


G
Gordon Davisson

*/ 是匹配当前目录中所有子目录的模式(* 将匹配所有文件 子目录;/ 将其限制为目录)。同样,要列出 /home/alice/Documents 下的所有子目录,请使用 ls -d /home/alice/Documents/*/


请注意,*/ 不会匹配任何隐藏文件夹。要包含它们,要么像 ls -d .*/ */ 那样明确指定它们,要么在 Bash 中指定 set the dotglob option
@GordonDavisson 使用 bash 选项 shopt -s nullglob 可以避免失败消息
@BinaryZebra 设置 nullglob 将避免错误消息,但会导致更多混乱:设置 nullglob 且没有子目录,ls */ 将扩展为仅 ls,这将列出当前目录中的所有文件。我很确定在这种情况下这不是你想要的。
*/ 还将子目录的名称设置为以斜杠结尾。
列出所有文件夹,不包括 ./ ../ls -d */ .[^.]*/
I
Iulian Onofrei

完成此任务的四种方法,每种方法都有不同的输出格式

1.使用回声

示例:echo */echo */*/
这是我得到的:

cs/ draft/ files/ hacks/ masters/ static/  
cs/code/ files/images/ static/images/ static/stylesheets/  

2. 仅使用 ls

示例:ls -d */
这正是我得到的:

cs/     files/      masters/  
draft/  hacks/      static/  

或作为列表(带有详细信息):ls -dl */

3. 使用 ls 和 grep

示例:ls -l | grep "^d" 这是我得到的:

drwxr-xr-x  24 h  staff     816 Jun  8 10:55 cs  
drwxr-xr-x   6 h  staff     204 Jun  8 10:55 draft  
drwxr-xr-x   9 h  staff     306 Jun  8 10:55 files  
drwxr-xr-x   2 h  staff      68 Jun  9 13:19 hacks  
drwxr-xr-x   6 h  staff     204 Jun  8 10:55 masters  
drwxr-xr-x   4 h  staff     136 Jun  8 10:55 static  

4. Bash 脚本(不推荐用于包含空格的文件名)

示例:for i in $(ls -d */); do echo ${i%%/}; done
这是我得到的:

cs  
draft  
files  
hacks  
masters  
static

如果您希望以“/”作为结束字符,命令将是:for i in $(ls -d */); do echo ${i}; done

cs/  
draft/  
files/  
hacks/  
masters/  
static/

注意。 3 对我来说明显比其他人慢。在我测试的目录中:1 .012s、2 .016s、3 .055s4 .021s。
@isomorphismes,您是如何测量时间的?怎么做?顺便说一句,我不得不说,第 1 是我最喜欢的。
Albert,我使用了 Unix 函数 time。 /// 我同意,echo */ls -d */ 更聪明。
您应该注意的两件小事。 ls -l | grep "^d" 过滤掉目录的符号链接,而 'ls -d */' 显示它们。此外,如果目标目录中根本不存在任何目录,则“ls -d */”会失败。
在处理包含空格的文件夹名称时,1. 选项会造成很大的麻烦。
P
Peter Mortensen

我用:

ls -d */ | cut -f1 -d'/'

这会创建一个没有斜杠的单列 - 在脚本中很有用。


ls-1 选项也将以单列格式输出,就像在 ls -1 -d */ 中一样。
@user29020 应该注意 -1 仍然为每个条目输出一个斜杠。
当我将此作为别名添加到 .bashrc 时,如何添加 '/'
@RNA 迟到了回答,但对于未来的人:尝试用反斜杠转义? '\/'
如果有前导斜线则中断。这仅删除尾部斜杠:| sed -e 's-/$--'
P
Peter Mortensen

对于所有没有子文件夹的文件夹:

find /home/alice/Documents -maxdepth 1 -type d

对于所有带有子文件夹的文件夹:

find /home/alice/Documents -type d

为了匹配问题(但包括点文件),第一个应该是:find /home/alice/Documents -maxdepth 1 -mindepth 1 -type d 否则你包括 /home/alice/Documents 本身。要包含指向目录的符号链接,请以 -L 为前缀
这似乎是最明智的解决方案,因为 find 是实际为此任务制作的工具。您可以通过管道排除第一个结果 - 当前目录的 ./ - grep -v '^\./$'
P
Peter Mortensen

四个(更多)可靠的选择。

未引用星号 * 将被 shell 解释为模式(glob)。 shell 将在路径名扩展中使用它。然后它将生成与该模式匹配的文件名列表。

一个简单的星号将匹配 PWD(当前工作目录)中的所有文件名。像 */ 这样更复杂的模式将匹配所有以 / 结尾的文件名。因此,所有目录。这就是为什么命令:

1.-回声。

echo */
echo ./*/              ### Avoid misinterpreting filenames like "-e dir"

将(通过 shell)扩展为 echo PWD 中的所有目录。

要对此进行测试:创建一个名为 test-dir 的目录 (mkdir),然后将 cd 放入其中:

mkdir test-dir; cd test-dir

创建一些目录:

mkdir {cs,files,masters,draft,static}   # Safe directories.
mkdir {*,-,--,-v\ var,-h,-n,dir\ with\ spaces}  # Some a bit less secure.
touch -- 'file with spaces' '-a' '-l' 'filename'    # And some files:

即使使用奇怪的命名文件,命令 echo ./*/ 也将保持可靠:

./--/ ./-/ ./*/ ./cs/ ./dir with spaces/ ./draft/ ./files/ ./-h/
./masters/ ./-n/ ./static/ ./-v var/

但是文件名中的空格使阅读有点混乱。

如果不是 echo,我们使用 ls。外壳仍然是扩展文件名列表的东西。 shell 是在 PWD 中获取目录列表的原因。 ls-d 选项使其列出当前目录条目,而不是每个目录的内容(默认显示)。

ls -d */

但是,此命令(有点)不太可靠。它会因上面列出的奇怪的命名文件而失败。它会被几个名字窒息。您需要一一擦除,直到找到有问题的。

2.- ls

GNU ls 将接受“选项结束”(--)键。

ls -d ./*/                     ### More reliable BSD ls
ls -d -- */                    ### More reliable GNU ls

3.-printf

要在自己的行中列出每个目录(在一列中,类似于 ls -1),请使用:

$ printf "%s\n" */        ### Correct even with "-", spaces or newlines.

而且,更好的是,我们可以删除结尾的 /

$ set -- */; printf "%s\n" "${@%/}"        ### Correct with spaces and newlines.

像这样的尝试

$ for i in $(ls -d */); do echo ${i%%/}; done

将失败:

一些名称(ls -d */)如上所示。

会受到 IFS 值的影响。

将在空格和制表符上拆分名称(使用默认 IFS)。

名称中的每个换行符都会启动一个新的 echo 命令。

4.- 功能

最后,在函数中使用参数列表不会影响当前运行的 shell 的参数列表。简单地

$ listdirs(){ set -- */; printf "%s\n" "${@%/}"; }
$ listdirs

提供此列表:

--
-
*
cs
dir with spaces
draft
files
-h
masters
-n
static
-v var

这些选项对于几种类型的奇数文件名是安全的。


P
Peter Mortensen

tree 命令在这里也非常有用。默认情况下,它将显示所有文件和目录的完整深度,其中一些 ASCII 字符显示目录树。

$ tree
.
├── config.dat
├── data
│   ├── data1.bin
│   ├── data2.inf
│   └── sql
|   │   └── data3.sql
├── images
│   ├── background.jpg
│   ├── icon.gif
│   └── logo.jpg
├── program.exe
└── readme.txt

但是,如果我们只想获取目录,没有 ASCII 树,并且使用当前目录的完整路径,您可以这样做:

$ tree -dfi
.
./data
./data/sql
./images

论据是:

-d     List directories only.
-f     Prints the full path prefix for each file.
-i     Makes tree not print the indentation lines, useful when used in conjunction with the -f option.

如果你想要绝对路径,你可以从指定当前目录的完整路径开始:

$ tree -dfi "$(pwd)"
/home/alice/Documents
/home/alice/Documents/data
/home/alice/Documents/data/sql
/home/alice/Documents/images

并且要限制子目录的数量,您可以使用 -L level 设置子目录的最大级别,例如:

$ tree -dfi -L 1 "$(pwd)"
/home/alice/Documents
/home/alice/Documents/data
/home/alice/Documents/images

使用 man tree 可以看到更多参数。


P
Peter Mortensen

如果您想知道为什么 'ls -d */' 的输出会给您两个斜杠,例如:

[prompt]$ ls -d */
app//  cgi-bin//  lib//        pub//

这可能是因为您的 shell 或会话配置文件在某处将 ls 命令别名为包含 -F 标志的 ls 版本。该标志将一个字符附加到每个输出名称(不是纯文件),指示它的类型。所以一个斜线来自匹配模式'*/',另一个斜线是附加的类型指示符。

为了摆脱这个问题,你当然可以为 ls 定义一个不同的别名。但是,要暂时不调用别名,您可以在命令前加上反斜杠:

\ls -d */

P
Peter Mortensen

实际的 ls 解决方案,包括指向目录的符号链接

这里的许多答案实际上并未使用 ls(或仅在 ls -d 的琐碎意义上使用它,而使用通配符进行实际的子目录匹配。真正的 ls 解决方案很有用,因为它允许使用 { 1} 排序选项等。

排除符号链接

已经给出了一种使用 ls 的解决方案,但它与其他解决方案的不同之处在于它排除了指向目录的符号链接

ls -l | grep '^d'

(可能通过 sedawk 管道以隔离文件名)

包括符号链接

在应该包含指向目录的符号链接的(可能更常见的)情况下,我们可以使用 ls-p 选项,这使它在目录名称(包括符号链接的名称)后附加一个斜杠字符:

ls -1p | grep '/$'

或者,去掉尾部的斜杠:

ls -1p | grep '/$' | sed 's/\/$//'

我们可以根据需要向 ls 添加选项(如果使用长列表,则不再需要 -1)。

注意:如果我们想要尾部斜杠,但不希望它们被 grep 突出显示,我们可以通过将行的实际匹配部分设为空来粗略地移除突出显示:

ls -1p | grep -P '(?=/$)'

P
Peter Mortensen

当前目录的简单列表,它将是:

ls -1d */

如果你想要它排序和清洁:

ls -1d */ | cut -c 1- | rev | cut -c 2- | rev | sort

请记住:大写字符在排序中具有不同的行为


P
Peter Mortensen

如果不需要列出隐藏目录,我提供:

ls -l | grep "^d" | awk -F" " '{print $9}'

如果需要列出隐藏目录,请使用:

ls -Al | grep "^d" | awk -F" " '{print $9}'

或者

find -maxdepth 1 -type d | awk -F"./" '{print $2}'

如果您需要了解有关 awk 的更多信息,请查看此answer
与其他答案相比,“ls .. | grep ...| awk”的第一个选项似乎过多的脚本。
您假设没有目录在其名称中包含空格。
ls -l | awk '/^d/ {print $9}' 这就是我想出来的:) 既然已经竖起大拇指了!
ls -l | awk '/^d/ {print $9}' 有效,没有目录时其他解决方案无效
P
Peter Mortensen

我只是将它添加到我的 .bashrc 文件中(如果您只需要/想要一个会话,您也可以在命令行上键入它):

alias lsd='ls -ld */'

然后 lsd 将产生所需的结果。


你就不能用吗? ls -l 路径 | grep 博士
“然后 lsd 将产生所需的结果。”我笑
根据我的经验,它会产生结果。
我使用“lad”(列出所有目录),还包括“.*/”以包含隐藏目录。当然,我也不会失去影射。
v
vinzee

这是我正在使用的

ls -d1 /Directory/Path/*;

这实际上是一个很好的解决方案,可以逐行显示。
它不会只列出目录。您必须添加尾部斜杠:ls -d1 /Directory/Path/*/
是的。感谢您的评论。要列出我当前路径中的目录,我必须这样做:ls -d1 ./*/ 或这个 ls -d1 */
P
Peter Mortensen

仅列出目录:

ls -l | grep ^d

仅列出文件:

ls -l | grep -v ^d 

或者你也可以这样做:

ls -ld */

P
Peter Mortensen

试试这个。它适用于所有 Linux 发行版。

ls -ltr | grep drw

ls -l | grep '^d' | awk '{print $9}'
P
Peter Mortensen

要显示不带 / 的文件夹列表:

ls -d */|sed 's|[/]||g'

ls -d1 */ | tr -d "/"
无需调用外部命令:set -- */; printf "%s\n" "${@%/}"
我喜欢@wholanda 的解决方案。我的稍微短一点的解决方案是(经过测试和工作): ls -d */|sed 's|/||g'
还有一个 lsdir 别名也很有用: alias lsdirs="ls -d */ | sed 's|/||g'"
m
muru

测试该项目是否为具有 test -d 的目录:

for i in $(ls); do test -d $i && echo $i ; done

请解释这段代码的作用,以及它与问题的关系。
它运行命令'ls'然后循环输出测试,如果每个都是一个目录,如果是,则回显..工作但有更好的方法
@ShoeLace:有什么更好的方法?他们中的一些人在这里的答案中有代表吗?
D
DevWL

ls 和 awk(没有 grep)

ls -l | awk '/^d/ {print $9}'

其中 ls -l 列出具有权限的文件
awk 过滤输出
'/^d/' 正则表达式,仅搜索以字母 d 开头的行(作为目录)查看第一行 - 权限
{print}将打印所有列
{print $9} 将仅打印来自 ls -l 输出第 9 列(名称)

非常简单干净


w
warfreak92

仅供参考,如果您想在多行中打印所有文件,您可以执行 ls -1 将每个文件打印在单独的行中。文件 1 文件 2 文件 3


P
Peter Mortensen

*/ 是匹配当前目录中目录的文件名匹配模式。

只列出目录,我喜欢这个功能:

# Long list only directories
llod () {
  ls -l --color=always "$@" | grep --color=never '^d'
}

把它放在你的 .bashrc 文件中。

使用示例:

llod       # Long listing of all directories in current directory
llod -tr   # Same but in chronological order oldest first
llod -d a* # Limit to directories beginning with letter 'a'
llod -d .* # Limit to hidden directories

注意:如果您使用 -i 选项,它将中断。这是一个修复:

# Long list only directories
llod () {
  ls -l --color=always "$@" | egrep --color=never '^d|^[[:digit:]]+ d'
}

P
Peter Mortensen
file * | grep directory

输出(在我的机器上)——

[root@rhel6 ~]# file * | grep directory
mongo-example-master:    directory
nostarch:                directory
scriptzz:                directory
splunk:                  directory
testdir:                 directory

使用 cut 可以进一步细化上述输出:

file * | grep directory | cut -d':' -f1
mongo-example-master
nostarch
scriptzz
splunk
testdir

* could be replaced with any path that's permitted
 file - determine file type
 grep - searches for string named directory
 -d - to specify a field delimiter
 -f1 - denotes field 1

u
user9342572809

仅从“此处”列出目录的单行代码。

带文件数。

for i in `ls -d */`; do g=`find ./$i -type f -print| wc -l`; echo "Directory $i contains $g files."; done

g
glennsl

使用 Perl:

ls | perl -nle 'print if -d;'

P
Peter Mortensen

我部分解决了它:

cd "/path/to/pricipal/folder"

for i in $(ls -d .*/); do sudo ln -s "$PWD"/${i%%/} /home/inukaze/${i%%/}; done

    ln: «/home/inukaze/./.»: can't overwrite a directory
    ln: «/home/inukaze/../..»: can't overwrite a directory
    ln: accesing to «/home/inukaze/.config»: too much symbolics links levels
    ln: accesing to «/home/inukaze/.disruptive»: too much symbolics links levels
    ln: accesing to «/home/inukaze/innovations»: too much symbolics links levels
    ln: accesing to «/home/inukaze/sarl»: too much symbolics links levels
    ln: accesing to «/home/inukaze/.e_old»: too much symbolics links levels
    ln: accesing to «/home/inukaze/.gnome2_private»: too much symbolics links levels
    ln: accesing to «/home/inukaze/.gvfs»: too much symbolics links levels
    ln: accesing to «/home/inukaze/.kde»: too much symbolics links levels
    ln: accesing to «/home/inukaze/.local»: too much symbolics links levels
    ln: accesing to «/home/inukaze/.xVideoServiceThief»: too much symbolics links levels

好吧,这减少了我的主要部分:)


C
Community

这是使用 tree 的变体,它仅在单独的行上输出目录名称,是的,它很难看,但是嘿,它可以工作。

tree -d | grep -E '^[├|└]' | cut -d ' ' -f2

或使用 awk

tree -d | grep -E '^[├|└]' | awk '{print $2}'

但是,这可能会更好,并且会在目录名称之后保留 /

ls -l | awk '/^d/{print $9}'

A
Avinash Raut

如果您的文件夹名称中有空间 $9 print 将不起作用,请尝试以下命令

ls -l yourfolder/alldata/ | grep '^d' | awk '{print $9" " $10}'

输出

ls -l yourfolder/alldata/ | grep '^d' | awk '{print $9" " $10}'
testing_Data 
Folder 1

t
torbatamas

我发现这个解决方案最舒服,我添加到列表中:

find * -maxdepth 0 -type d

不同的是,它没有./开头,文件夹名是可以使用的。


f
flow2k

要回答最初的问题,*/ls 本身无关;它是由 shell/Bash 在称为 globbing 的过程中完成的。

这就是 echo */ls -d */ 输出相同元素的原因。 (-d 标志使 ls 输出目录名称而不是目录的内容。)


P
Peter Mortensen

添加使其完整循环,检索每个文件夹的路径,使用 Albert 的答案以及 Gordans 的组合。那应该很有用。

for i in $(ls -d /pathto/parent/folder/*/); do echo ${i%%/}; done

输出:

/pathto/parent/folder/childfolder1/
/pathto/parent/folder/childfolder2/
/pathto/parent/folder/childfolder3/
/pathto/parent/folder/childfolder4/
/pathto/parent/folder/childfolder5/
/pathto/parent/folder/childfolder6/
/pathto/parent/folder/childfolder7/
/pathto/parent/folder/childfolder8/

P
Peter Mortensen

这是我用于仅列出目录名称的内容:

ls -1d /some/folder/*/ | awk -F "/" "{print \$(NF-1)}"