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

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

我有一个目录,我想在其中列出所有内容(文件和子目录)而不显示符号链接。我在 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)。

答案1

对于所述问题,您可以使用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 显示文件名,即使它恰好与单个匹配文件一起运行。

答案2

或者,更简单:

ls -l | grep -v ^l

解释

ls -l意思是列出来长表。执行此操作时,第一个字符串会提供有关每个文件的信息。第一个字符表示每个文件的类型。如果它是符号链接,则 anl是第一个字符。

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

答案3

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

-r, --递归

仅当符号链接位于命令行时,才以递归方式读取每个目录下的所有文件。这相当于 -d 递归选项。

-R, --取消引用递归

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

答案4

您可以用来$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 hack 可能过于复杂 - 有一个广泛可用的接口来分配这些值。尝试dircolors -p在你的 cli 中info dircolors获取更多信息。

您可以将文件名包装在任意字符串中。如果您愿意,可以将它们注释掉。您可以仅根据文件扩展名指定类似的行为。确实没有什么是你不能这样指定的。

现在我也不只是编造这一切——我是在偶然发现源代码意外地。

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

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

  2. ${type_code}- 紧接在每个文件名之前,以包含文件类型的缩写,并且始终出现在同一行,之后有 7 个空格分隔的字段$no 或者紧跟在->表示符号链接目标的 a 之后。

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

  4. 所有其他值均为空。

接下来是一个空分隔的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 --是子 shell 中应该能够可靠地从ls输出中删除您可能想要的文件类型的任何组合,而不管文件名可能包含的任何字符。

相关内容