使用 grep 过滤 ls 输出出现意外结果

使用 grep 过滤 ls 输出出现意外结果

我目前正在使用grep和解决一个问题ls。目标是列出当前目录中作为链接文件的所有行。我的目录中有 3 个链接文件,但是当我执行命令时它只显示一个。

这是我正在输入的内容:

ls -lR | grep l*

任何帮助,将不胜感激。谢谢

答案1

@NasirRiley 走在正确的轨道上。要列出当前目录中的符号链接,请运行find . -mindepth 1 -maxdepth 1 -type l.测试:

$ cd "$(mktemp --directory)"
$ mkdir foo
$ touch foo/bar baz
$ ln --symbolic foo/bar ban
$ ln --symbolic bar foo/bat # symlink in subdirectory, should be ignored
$ find . -mindepth 1 -maxdepth 1 -type l
./ban

答案2

您的管道存在一些问题。

  1. 解析输出ls 这不是一个好主意(也可以看看为什么*不*解析`ls`(以及该怎么做)?)。它的格式没有标准化,文件名可以包含除 NUL 和/.因此,它不保证以明确的形式列出文件名。经常给出的示例涉及换行符(请注意ls以不同方式调用可能会导致不同的、可能不明确的结果):

    $ touch 'foo
    > bar'
    $ ls -1
    'foo'$'\n''bar'
    $ ls | cat
    foo
    bar
    

    foo和 是bar两个不同的文件或同一文件名的两个部分吗?

    递归搜索目录中给定类型文件的安全方法是find

  2. 未转义的字符串l*被 shell 解释为通配表达。它扩展为文件名列表(通过广泛的“文件”的定义l) 从当前目录开始。

    # In a directory you created for testing purposes
    $ rm *; touch foo; ln -s foo link1; ln -s foo link2; ln -s foo link3
    $ set -x; ls -lR | grep l*
    + ls -lR
    + grep link1 link2 link3
    

    shellxtrace选项(即set -x,在多个 shell 中可用并由POSIX) 对于显示文件名扩展(通配)的效果很有用:l*扩展为link1 link2 link3并因此在 的内容中grep搜索字符串(通过符号链接和)。 (link1foolink2link3grep当在要搜索的模式之后给出文件名列表时,不读取标准输入)。

    如果你恰好有名称以以下字符开头的文件l

    # In a directory you created for testing purposes
    $ rm *; touch foo; ln -s foo link1; ln -s foo Link2; ln -s foo Link3
    $ set -x; ls -lR | grep l*
    + ls -lR
    + grep link1
    lrwxrwxrwx 1 user group 3 May  1 03:04 link1 -> foo
    

    然后在grep其标准输入( 的输出ls)中搜索字符串link1,此处匹配一行。 (读取标准输入是grep在没有给出文件名或文件名参数为 时执行的操作-)。

    你应该引用文字字符串作为参数传递,以防止 shell 执行文件名扩展。作为替代方案,在 shell 支持的情况下,可以使用set -f.

  3. 如果当前目录中没有文件名以 开头,则通配表达式保持不变并作为第一个位置参数l传递。然后将其解释为正则表达式(默认为grepgrepBRE变种)其内容为“对于任何输入行,匹配一个选修的 l(任何地方)”,有效匹配任何内容:

    # In a directory you created for testing purposes
    $ rm *; touch foo
    $ ls -lR
    .:
    total 0
    -rw-r--r-- 1 user group 0 May  1 02:49 foo
    $ set -x; ls -lR | grep l*
    + ls -lR
    + grep 'l*'
    .:
    total 0
    -rw-r--r-- 1 user group 0 May  1 03:14 foo
    

    要匹配以文字开头的字符串,l您需要一个锚定表达式:grep '^l'

答案3

正如您所知,您正在寻找的命令是:

ls -l | grep '^l'

不一定需要引号。

删除-Ron 选项ls是因为您指定需要当前目录,而不是目录树。

无论哪种方式,指向您的答案find可能是更好的解决方案。

相关内容