![使用 LS 命令列出目录时的文件类型和取消引用](https://linux22.com/image/38924/%E4%BD%BF%E7%94%A8%20LS%20%E5%91%BD%E4%BB%A4%E5%88%97%E5%87%BA%E7%9B%AE%E5%BD%95%E6%97%B6%E7%9A%84%E6%96%87%E4%BB%B6%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%8F%96%E6%B6%88%E5%BC%95%E7%94%A8.png)
我正在尝试将ls
命令的参数组合起来以列出目录内容。我基本上想要实现的是列出取消引用所有链接的目录,但明确显示列出的项目是一个链接。我尝试组合--dereference
和--classify
选项,但我没有显示链接符号 ( @
),而是得到了*
,因为链接的目标是可执行文件。
关于我如何才能得到这样的结果有什么想法吗?我对ls
命令以外的其他选择持开放态度。
编辑:
我实际上使用了命令中的其他选项ls
。我当前的命令及其选项如下:
ls -ogq -LB --group-directories-first --time-style=long-iso
我打算解析我正在构建的应用程序内的输出,并且无法使用带有箭头 ( ->
) 的默认链接输出。目录中的其他项目(例如文件夹和文件)也必须列出。
编辑(2):
澄清一下,我正在开发一个 Java 应用程序,它使用 SSH2 API 连接到服务器并列出目录。然后使用 jsTree jQuery 插件将列表中的结果用于填充树。目前我上面引用的命令给出了以下输出:
felipe@simba:/mnt/drive$ ls -ogq --group-directories-first --time-style=long-iso
total 12
drwxr-sr-x 2 4096 2014-06-11 18:04 folder1
drwxr-sr-x 6 4096 2014-06-27 19:35 folder2
dr-Sr-s-wt 2 4096 2014-06-27 13:51 folderWithPermissions
-rw-r--r-- 1 0 2014-06-30 10:42 file.txt
lrwxrwxrwx 1 49 2014-06-30 11:36 linkTeste -> folder2/dir/otherfile.txt
通过应用正则表达式,我可以通过查看权限来识别什么是文件夹、文件或链接。但是当我有一个链接时,我只需要列出链接名称,而不是name -> destination
.如果我使用命令-L
的选项,ls
则仅输出链接名称,并且获得引用的目标的权限(这是一件好事),因为该-L
选项取消引用链接,但这样我就无法知道该链接实际上是一个关联。
felipe@simba:/mnt/drive$ ls -ogq -L --group-directories-first --time-style=long-iso
total 12
drwxr-sr-x 2 4096 2014-06-11 18:04 folder1
drwxr-sr-x 6 4096 2014-06-27 19:35 folder2
dr-Sr-s-wt 2 4096 2014-06-27 13:51 folderWithPermissions
-rw-r--r-- 1 0 2014-06-30 10:42 file.txt
-rwxr-xr-x 1 0 2014-06-27 18:40 linkTeste
我只需要列出链接名称,知道它是一个链接并知道目的地是什么(文件、文件夹或链接)。我可以处理不同类型的输出,因为无论如何我都会应用正则表达式。
也欢迎使用find
或 的替代方案。stat
答案1
编辑以回应更新的问题
由于您只关心链接、目录和常规文件,并且不需要处理ls
可以识别的其他文件类型(FIFO、套接字等),因此您可以执行类似stat
.对于下面的示例,我创建了以下测试环境:
$ ls -l
total 4.0K
-rw-r--r-- 1 terdon terdon 0 Jun 30 23:12 a new?line
-rw-r--r-- 1 terdon terdon 0 Jun 30 23:12 a space
-rw-r--r-- 1 terdon terdon 0 Jun 30 23:12 a?tab
drwxr-xr-x 2 terdon terdon 4.0K Jun 30 23:11 dir1
lrwxrwxrwx 1 terdon terdon 4 Jun 30 23:13 linktodir1 -> dir1
lrwxrwxrwx 1 terdon terdon 7 Jun 30 23:13 sh -> /bin/sh
正如您所看到的,其中包括链接、可执行文件的链接、带空格的文件名、带制表符 ( \t
) 的文件名和带换行符 ( \n
) 的文件名。这些文件中的大多数都会破坏您的ls
方法,但stat
可以正确处理它们:
$ stat --printf "%A\t%N\t%F\n" *
-rw-r--r-- ‘a new\nline’ regular file
-rw-r--r-- ‘a space’ regular file
-rw-r--r-- ‘a\ttab’ regular file
drwxr-xr-x ‘dir1’ directory
lrwxrwxrwx ‘linktodir1’ -> ‘dir1’ symbolic link
lrwxrwxrwx ‘sh’ -> ‘/bin/sh’ symbolic link
相关部分man stat
:
--printf=格式
与 --format 类似,但解释反斜杠转义,并且不输出强制的尾随换行符。如果您想要换行符,请在 FORMAT 中包含 \n
%A 人类可读形式的访问权限
%F 文件类型
%N 带引号的文件名,如果是符号链接则取消引用
请注意,字段之间用 分隔\t
,这意味着您将能够优雅地处理字段中的空格(例如文件名中的空格)。
你提到你无法应对->
。我不完全确定为什么,但你可以用sed
$ stat --printf "%A\t%N\t%F\n" * | sed 's/->//'
lrwxrwxrwx ‘linktodir1’ ‘dir1’ symbolic link
或用另一个字符串替换它:
$ stat --printf "%A\t%N\t%F\n" * | sed 's/->/→/' | grep linktodir
lrwxrwxrwx ‘linktodir1’ → ‘dir1’ symbolic link
或者只是解析文件类型。
根据您想要执行的操作,将您正在搜索的三种文件类型分开并单独处理可能会很有用。如果是这样,请使用find
1及其-printf
选项:
$ find ./ -maxdepth 1 -mindepth 1 -type f -printf '%M\t%P\t%l\n' ## files
$ find ./ -maxdepth 1 -mindepth 1 -type d -printf '%M\t%P\t%l\n' ## directories
$ find ./ -maxdepth 1 -mindepth 1 -type l -printf '%M\t%P\t%l\n' ## links
在这种情况下,printf
指令是
%M File's permissions (in symbolic form, as for ls). This
directive is supported in findutils 4.2.5 and later.
%P File's name with the name of the command line argument
under which it was found removed.
%l Object of symbolic link (empty string if file is not a
symbolic link).
您还可以将上述内容组合成一个命令(使用find
's-o
运算符),但它允许您-printf
根据文件类型打印任意字符串。例如:
$ find ./ -maxdepth 1 -mindepth 1 \( -type l -printf 'link:\t%M\t%P\t%l\n' \) \
-o \( -type d -printf 'dir:\t%M\t%P\n' \) \
-o \( -type f -printf 'file:\t%M\t%P\n' \)
file: -rw-r--r-- a?tab
file: -rw-r--r-- a space
link: lrwxrwxrwx linktodir1 dir1
file: -rw-r--r-- a new?line
dir: drwxr-xr-x dir1
link: lrwxrwxrwx sh /bin/sh
如果上面的命令的输出未显示在终端上,则该命令将正确解释\t
。\n
但是,要正确处理带有换行符的文件名,您在解析时需要小心(确保“行”以 开头[file|dir|link]:
)或\0
在每次调用中用作行终止符printf
而不是\n
:
$ find ./ -maxdepth 1 -mindepth 1 \( -type l -printf 'link:\t%M\t%P\t%l\0' \) \
-o \( -type d -printf 'dir:\t%M\t%P\0' \) \
-o \( -type f -printf 'file:\t%M\t%P\0' \)
1 -maxdepth
和-mindepth
是 GNU 扩展,因此这种方法仅适用于 GNU find
。
以下内容作为问题的第一个不太具体版本的解决方案发布。我将它们留在这里,因为它们可能对其他人有用。
壳牌和
readlink
for f in *; do readlink "$f" >/dev/null && echo "$(readlink -f "$f") (link)" || echo "$f"; done
输出示例:
/etc (link) foo sample.R sample.R~
上面的循环遍历当前文件和目录下的所有文件和目录,如果
readlink
返回成功(如果$f
是链接),它将取消引用它(readlink -f
,请注意,这将遵循全部链接。如果您只需要第一级,请删除-f
) 并与 一起打印目标(link)
。如果不是,它只会打印$f
。如果这只是为了你而不是为了被解析,只需使用
ls -l
:$ ls -l total 512116 -rw-r--r-- 1 terdon terdon 100641 Jun 30 19:10 er lrwxrwxrwx 1 terdon terdon 5 Jun 30 19:12 etc -> /etc/ -rw-r--r-- 1 terdon terdon 524288000 Jun 30 19:10 foo -rwxr--r-- 1 terdon terdon 353 Jun 30 15:22 sample.R -rwxr--r-- 1 terdon terdon 249 Jun 30 14:51 sample.R~
这将清楚地表明与 的链接
link -> target
。