使用 LS 命令列出目录时的文件类型和取消引用

使用 LS 命令列出目录时的文件类型和取消引用

我正在尝试将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

或者只是解析文件类型。


根据您想要执行的操作,将您正在搜索的三种文件类型分开并单独处理可能会很有用。如果是这样,请使用find1及其-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


以下内容作为问题的第一个不太具体版本的解决方案发布。我将它们留在这里,因为它们可能对其他人有用。

  1. 壳牌和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

  2. 如果这只是为了你而不是为了被解析,只需使用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

相关内容