ls目录的内容忽略符号链接


17

我有一个目录,我想在其中列出所有内容(文件和子目录)而不显示符号链接。我在Linux上使用GNU实用程序。该ls版本是8.13。

例:

完整目录清单:

~/test$ ls -Gg
total 12
drwxrwxr-x 2 4096 Jul  9 10:29 dir1
drwxrwxr-x 2 4096 Jul  9 10:29 dir2
drwxrwxr-x 2 4096 Jul  9 10:29 dir3
-rw-rw-r-- 1    0 Jul  9 10:29 file1
-rw-rw-r-- 1    0 Jul  9 10:29 file2
lrwxrwxrwx 1    5 Jul  9 10:29 link1 -> link1
lrwxrwxrwx 1    5 Jul  9 10:30 link2 -> link2

我想得到什么

~/test$ ls -somthing (or bash hack)
total 12
dir1 dir2 dir3 file1 file2

注意:我的主要动机是在不遵循符号链接的情况下进行递归grep(GNU grep 2.10)。

Answers:


28

对于陈述的问题,您可以使用find

find . -mindepth 1 ! -type l

将列出当前目录或不是符号链接的任何子目录中的所有文件和目录。

mindepth 1只是跳过.当前目录条目。它的实质是的组合-type l,表示“是符号链接”,和!表示否定以下测试。结合起来,它们匹配不是符号链接的每个文件。这将递归列出所有文件和目录,但没有符号链接。

如果只需要常规文件(而不是目录):

find . -type f

只包括该目录的直接子级,不包括所有其他子级:

find . -mindepth 1 -maxdepth 1

您可以将这些(和其他)测试结合在一起,以获得所需的文件列表。

grep在与您正在使用的测试相匹配的每个文件上执行特定操作,请使用-exec

find . -type f -exec grep -H 'some pattern' '{}' +

'{}'将这些文件被替换。该+告知需要find你的命令完成。该选项将-H强制grep显示文件名,即使该文件恰巧与单个匹配文件一起运行。


它不会在找到模式的女巫中显示文件。
TheMeaningfulEngineer 2014年

这就是您grep要争取的(请参阅最后一段)。
Michael Homer 2014年

我不为我工作。它仅输出找到的模式,而没有找到文件名的文件名。
TheMeaningfulEngineer 2014年

2
grep -H如果有的话,请使用,(请参阅参考资料man grep),否则grep 'pat' '{}' /dev/null ';',请欺骗它,使您认为没有多个文件。
Michael Homer 2014年

1
+在简并的情况下(最后只剩下一个文件或一个文件),无法满足该要求。
Michael Homer 2014年

16

或者,更简单:

ls -l | grep -v ^l

说明

ls -l表示以长形式列出。执行此操作时,第一个字符字符串将提供有关每个文件的信息。第一个字符指示每个文件的类型。如果是符号链接,则l第一个字符为。

grep -v ^l表示过滤(-v)以(^)开头的行l


这很好用,但是如何仅获取文件夹名称?我想在for i in
Luka

你能解释一下这个代码吗?
Abg

要注意的是,如果你ommit这个解决方案不起作用-lls。因此,这将无法按预期工作:ls | grep -v ^l
stamster

@Luka您不会在的输出上循环播放find,请参见unix.stackexchange.com/questions/321697
Kusalananda

1
@abg-我添加了一个解释。希望能帮助到你。
杰夫

7

从版本2.12开始,-rGNU grep 的选项不会取消引用符号链接,除非您手动指定它们:

-r,-递归

仅在命令行上,才按照符号链接递归地读取每个目录下的所有文件。这等效于-d recurse选项。

-R,--dereference-递归

递归读取每个目录下的所有文件。跟随所有符号链接,与-r不同。


那是什么版本的grep。我-R, -r, --recursive Read all files under each directory, recursively; this is equivalent to the -d recurse option.在2.10版中
TheMeaningfulEngineer

grep(GNU grep)2.14
tijagi

5

在zsh中,这要归功于glob限定符

grep -- PATTERN **/*(.)

模式以**/递归方式遍历子目录。全局限定符.将匹配限制为常规文件。

如果没有zsh,请使用find(请参阅Michael Horner的答案)。在这种特殊情况下,GNU grep可以做您想要的事情(这正是它的grep -r作用)-但只有从2.12版开始,早期版本才遵循符号链接。


2

您可以$LS_COLORS用来执行此操作。如果您的ls支持版本使用该变量指定颜色,则可以定义每种文件类型的输出。它是内置行为,并且非常可配置。所以我创建了一些演示文件,例如:

for f in 9 8 7 6 5 4 3 2 1
    do touch "${f}file" && 
    ln -s ./"${f}file" ./"${f}filelink"
done

所以现在我要做:

LS_COLORS='lc=:rc=:ec=:ln=\n\n\0HERE_THERE_BE_A_LINK>>\0:' \
ls -1 --color=always | cat

###OUTPUT###
1file


HERE_THERE_BE_A_LINK>>1filelink@
2file


HERE_THERE_BE_A_LINK>>2filelink@
3file

...
HERE_THERE_BE_A_LINK>>8filelink@
9file
...

空值也在那里...

LS_COLORS='lc=:rc=:ec=:ln=\n\n\0HERE_THERE_BE_A_LINK>>\0:' \
ls -1 --color=always | sed -n l
1file$
$
$
\000HERE_THERE_BE_A_LINK>>\0001filelink@$
2file$
$
$
\000HERE_THERE_BE_A_LINK>>\0002filelink@$
3file$
...

您可以指定所有或任何文件类型。尽管仅ls合并了一些用于终端转义的默认编译值,但仅针对单个文件类型可能无法实现。您最好将api作为单个接口来解决。这是解析和分配当前环境dircolors配置的默认值的简单方法:

LS_COLORS='rs=:no=//:lc=:rc=:ec=//:'$(
set -- di fi ln mh pi so do bd cd or su sg ca tw ow st ex
for fc do printf %s "$fc=/$fc//:"
done) ls -l --color=always | cat

它在我的主目录中的输出如下所示:

total 884
///-rw-r--r-- 1 mikeserv mikeserv    793 Jul  9 11:23 /fi//1/
//drwxr-xr-x 1 mikeserv mikeserv    574 Jun 24 16:50 /di//Desktop//
//-rw-r--r-- 1 mikeserv mikeserv    166 Jul  4 23:02 /fi//Terminology.log/
//-rw-r--r-- 1 mikeserv mikeserv      0 Jul  6 11:24 /fi//new
file/
//lrwxrwxrwx 1 mikeserv mikeserv     10 Jul 11 04:18 /ln//new
file
link/ -> /fi//./new
file/
//-rwxr-xr-x 1 mikeserv mikeserv    190 Jun 22 11:26 /ex//script.sh/*
//-rw-r--r-- 1 mikeserv mikeserv 433568 Jun 22 17:10 /fi//shot-2014-06-22_17-10-16.jpg/
//-rw-r--r-- 1 mikeserv mikeserv     68 Jun 17 19:59 /fi//target.txt/

您也可以运行它,cat -A唯一的区别是您会看到$换行符- ls --color=always此配置不会引入不可打印的字符-只有您在这里看到的。

ls 插入其默认终端转义符,如下所示:

${lc}${type_code}${rc}FILENAME${lc}${rs}${rc}

...其中$lc (代码左侧)$rc (代码右侧)$rs (重置)的默认值为:

 \033 - ESCAPE
 m - END ESCAPE
 0 - reset 

...分别。${type_code}用于代表各种fi (常规文件-默认未设置)di (目录)ln (链接)以及我所知道的所有其他文件类型。还有$no (正常)默认情况下也是未设置的,这里用//每行开头的表示。我的简单小块IFS=:仅通过将每个可配置的名称插入其自身值并添加一个或两个斜杠的方式工作,尽管\0NUL字节也可以。

默认情况下,ls还将$rs在第一个输出之前插入一个$lc-但这在此处未正确表示。在这种情况下,我已指定$ec (结束代码),其代表为$rs在所有情况下-被指定当你没有得到额外的$rs之间$no${type_code}为您否则会-它只是呈现立即文件名以下,并在输出开始一次-正如您在第一行顶部的一个斜杠中看到的那样。

这是我自己的摘录 $LS_COLORS

printf %s "$LS_COLORS"

rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:\
so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:\
or=40;31;01:su=37;41:sg=30;43:ca=30;41:\
tw=30;42:ow=34;42:st=37;44:ex=01;32:\
*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:...

而且,实际上,我的小shell破解可能过于复杂-有一个广泛使用的接口可以分配这些值。尝试dircolors -p在您的CLI中info dircolors获取更多信息。

您可以将文件名包装在任意字符串中。您可以根据需要将其注释掉。您可以仅基于文件扩展名指定类似的行为。确实没有太多您无法指定这种方式。

现在,我不仅要解决所有这些问题,还因为偶然偶然涉足了源代码而了解了这一点。

使用此特定配置ls将发出:

  1. $no -在每个记录的开头每个记录一次

  2. ${type_code}-在每个文件名之前紧随其后,以包含文件类型的缩写,并且始终在与7个以空格分隔的字段相同的行上出现,该字段在表示符号链接的目标之后$no 之后->

  3. $ec -一次紧接在第一行之后,之后仅一次紧随每个文件名之后。

  4. 所有其他值均为空。

接下来是一个以null分隔的内容ls,这一次,我将使用cat -A,但如果没有它,它将与上一个示例相同:

LS_COLORS='rs=:no=\0//:lc=:rc=:ec=\0//:'$(
set -- di fi ln mh pi so do bd cd or su sg ca tw ow st ex
for fc do printf %s "$fc=/$fc//\0:"
done) ls -l --color=always | cat -A

total 884$
^@//^@//-rw-r--r-- 1 mikeserv mikeserv    793 Jul  9 11:23 /fi//^@1^@//$
^@//drwxr-xr-x 1 mikeserv mikeserv    574 Jun 24 16:50 /di//^@Desktop^@///$
^@//-rw-r--r-- 1 mikeserv mikeserv    166 Jul  4 23:02 /fi//^@Terminology.log^@//$
^@//-rw-r--r-- 1 mikeserv mikeserv      0 Jul  6 11:24 /fi//^@new$
file^@//$
^@//lrwxrwxrwx 1 mikeserv mikeserv     10 Jul 11 04:18 /ln//^@new$
file$
link^@// -> /fi//^@./new$
file^@//$
^@//-rwxr-xr-x 1 mikeserv mikeserv    190 Jun 22 11:26 /ex//^@script.sh^@//*$
^@//-rw-r--r-- 1 mikeserv mikeserv 433568 Jun 22 17:10 /fi//^@shot-2014-06-22_17-10-16.jpg^@//$
^@//-rw-r--r-- 1 mikeserv mikeserv     68 Jun 17 19:59 /fi//^@target.txt^@//$

因此,要可靠地从这样的ong列表中删除所有符号链接-l,您可以进行简单的更改:

LS_COLORS='rs=:no=//:lc=:rc=:ec=/ :'$(
set -- di fi mh pi so do bd cd or su sg ca tw ow st ex
for fc do printf %s "$fc=$fc/:"
done)ln=///: ls -l --color=always | sed ':ln
\|///|{N;\|\n//|!bln};s|.*//||'

我运行后的结果看起来像...

total 884
-rw-r--r-- 1 mikeserv mikeserv    793 Jul  9 11:23 fi/1/ 
drwxr-xr-x 1 mikeserv mikeserv    574 Jun 24 16:50 di/Desktop/ /
-rw-r--r-- 1 mikeserv mikeserv    166 Jul  4 23:02 fi/Terminology.log/ 
-rw-r--r-- 1 mikeserv mikeserv      0 Jul  6 11:24 fi/new
file/ 
-rwxr-xr-x 1 mikeserv mikeserv    190 Jun 22 11:26 ex/script.sh/ *
-rw-r--r-- 1 mikeserv mikeserv 433568 Jun 22 17:10 fi/shot-2014-06-22_17-10-16.jpg/ 
-rw-r--r-- 1 mikeserv mikeserv     68 Jun 17 19:59 fi/target.txt/ 

使用类似我上面的命令:

LSCOLORS=...$(...)fc1=///:fc2=///: ls ... | sed ...

... (子外壳中后面列出的文件类型fc1fc2位置set --应该用于可靠地从ls输出中删除您可能想要的文件类型的任何组合,而不考虑文件名可能包含的任何字符。


嘿,不错,+ 1代表创意。但是,目录看起来似乎有些cho塞,但它们的打印颜色是乱码的ANSI颜色代码。无论如何,您是否可以添加对此功能的解释?也许解释什么lcnc等有?
terdon

@terdon -他们只印有ANSI环境中的逃逸已设置并或作为默认的编译lsdi=价值。您需要添加di=:到var中以将其无效-以及其他所有条件。这就是api的意思-您可以处理每种文件类型,但在所有情况下都必须使用相同的接口。因此,设置ln一种方法并忽略di默认设置是行不通的。还有许多默认设置可以编译...嗯。您对询问lcnc和东西是有效的-完全-我已经做到了一天,但。我想将其链接。
mikeserv

哎呀,所以我要么总是指定所有可能的文件类型,要么先检查一下文件中存在的内容?好,谢谢。
terdon

@terdon-现在查看我的编辑-它在几行shell中完成所有工作,并通过其类型名称指定每种类型,并可靠地界定每个文件名。也没有引入不可打印的内容。而且无论如何都有一个api-它是dircolors。它读取一个配置文件并输出一个shell eval友好的var值。这很容易-但是那里的几行也是如此。无论如何,如果要使用dircolors它,只需保存两个不同的文件并以这种方式调用它。另外,我前几天向您展示了如何同时使用\0NUL分隔符作为每个转义序列的一部分来完成这两项操作。
mikeserv 2014年

@terdon-我试图弄清楚设置所有可能在其中编译的值有多么容易-我想我已经掌握了全部,也许太多了…… LS_COLORS='rs=:no=\0//:lc=:rc=:ec=\0//:'$( set -- di fi ln mh pi so do bd cd or su sg ca tw ow st ex; for fc do printf %s "$fc=/$fc//\0:"; done) ls -l --color=always | cat -A
mikeserv 2014年

0

上面的答案导致:

 ls -1F | grep -i "/"

奇怪的是,将1保留在ls命令之外仍然给出了一个列表。


1
为什么grep -i呢 它不是/大写还是小写。ls如果输出不是终端(此处为管道),则默认为noe列格式。
库萨兰达

-2

试试这个:

ls | grep -v " -> "

2
由于各种原因,该操作将失败,例如,在名为的文件上a -> b。对于带有换行符和其他奇怪内容的文件名,它也将失败。请阅读本文以了解为什么解析ls是个坏主意。
terdon

@terdon失败的更多根本原因。要么ls别名为ls -l,然后返回文件名之前的列,否则不返回,这对符号链接没有任何特殊作用。
吉尔(Gilles)'所以

@terdon-自我ls解析。我们ls每次打印到终端时都会解析-有一个api。我在这里发布了一个答案,展示了类似的内容-但您可以做更多的事情。前几天,我向您展示了-您自己使用了以空分隔的文件名。
mikeserv

@mikeserv我知道,我知道。但是,正如您自己演示的那样,解释如何安全地执行此操作需要花费几百行。从目前的情况来看,这个答案承受着解析ls的所有危险,而OP显然没有意识到它们。
terdon

@terdon- ls不会吃孩子或任何东西-只是一个程序。如果您不解释它,那么需要数百个解释,可能需要数百个解释为什么您刚刚链接的几百行是错误的。除此之外-这仅是两行:LS_COLORS='lc=:rc=:ec=:ln=\n\n\0HERE_THERE_BE_A_LINK>>\0:' \ ls -1 --color=always | cat
mikeserv

-3

试试这个命令: ls -p | grep -v @


不,列出链接。
TheMeaningfulEngineer 2014年

@Alan:k尝试一下find -type f
2014年

1
-1是因为:i)-p只是在目录中添加了一个斜线,您正在寻找-Fii)您的find替代项将不会列出目录,并且iii)请在发布前测试您的答案。
terdon
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.