【问题标题】:grep filename[asterisk] returns unexpected resultgrep 文件名 [星号] 返回意外结果
【发布时间】:2013-12-26 17:29:17
【问题描述】:

我有一个关于ls 命令的基本问题。 假设在一个目录中我有 4 个名为

的文件
run
run1
running
run.sh

所以,如果我这样做:ls -l|grep run*,那么我不会得到任何结果。

但如果我这样做ls -l|grep run.*,那么我会得到run.sh

但是我希望grep 列出这两种情况下的所有文件。 你能让我了解幕后发生的事情吗?

【问题讨论】:

  • grep 代表global regular expressions print 而不是global wildcard printrun* 是通配符语法; run.* 是正则表达式语法。
  • 另外注意不推荐解析ls。见mywiki.wooledge.org/ParsingLs
  • 我认为 ls 的输出仍然是允许的,不是吗?

标签: regex shell grep glob


【解决方案1】:

这是因为星号对 shell 来说是特殊的并且会被扩展。为避免这种情况,您必须引用 grep 的正则表达式才能看到它未展开:

ls -l|grep 'run*'

请注意,这不是您想要的,因为 'run*' 作为正则表达式意味着 'ru 后跟任意数量的 n'。这还将列出名为rubber 等的文件。要列出与 shell glob 模式(不同于正则表达式)匹配的文件,为什么不简单地使用

ls -l run*
ls -l run.*

并完全避免无用的 grep 过程?

【讨论】:

  • 嗯,这绝对不是我想要的,但现在我更困惑了。因为你说的似乎是对的,那么如果我写 ls run* 会怎样?为什么它在这里返回所有四个文件名?
  • 没错! “ls run*”相当于“ls run run1 running run.sh”
  • 好吧,我在问题中没有表达的主要内容是列出所有文件,无论其大小写如何。类似于ls -l|grep -i <filename>。因为 ls 不符合我必须这样做的目的。
【解决方案2】:

据我了解,“*”在执行命令本身之前由 shell 扩展,因此您的 grep 将尝试捕获包含所有文件名的字符串!另一方面,grep 需要一个正则表达式,因此“*”不会像您期望的那样解释。

直接的解决办法是:

$ ls -l run*

或者,如果您想使用 grep,则将“*”转义并提供正则表达式:

$ ls -l|grep run.\*
$ ls -l|grep 'run.*'

【讨论】:

  • 哦,是的,完全正确。我希望我能投票给你。可悲的是,它至少需要 15 名声望 :( 。非常感谢。
  • 如果任何答案帮助您解决了问题,您应该将其中一个标记为已接受的答案。编码愉快!
【解决方案3】:

在 shell 甚至运行 grep 之前,它会在您的命令中搜索任何未加引号的文件通配符,并对这些参数执行文件名扩展。

所以当你输入这个命令时:

ls -l | grep run*

shell 使用模式run* 搜索当前目录中的文件,并找到runrun1runningrun.sh。然后它用这些参数重写grep 命令:

ls -l | grep run run1 running run.sh

这会导致greprun1runningrun.sh 中搜索字符串run

如前所述,解决方案是将参数引用到 grep,这样 shell 就不会尝试对其执行文件名扩展:

ls -l | grep 'run.*'

【讨论】:

  • 确实如此。关于扩展的解释回答了我的第二个问题。但无论如何ls -l | grep run* 应该抛出一条消息说grep:No match 如果你写ls -l | grep runnnnn* 就会抛出它
  • 一点也不。请参阅我的回答:您在此目录中有四个文件,其名称以run 开头,因此run* 扩展为所有四个run run1 running run.sh。但是没有与runnnnn* 匹配的文件名,这就是shell 抛出该错误的原因。我不确定这里的混乱源自哪里。
  • 让我这样问:ls -l|grep run* 没有产生任何结果,那么为什么它不会抛出任何错误消息。另一方面,ls -l|grep runnnn* 也不会产生任何结果,但错误消息显示为 grep:No match。是什么导致 grep 在第一种情况下不抛出消息?
  • +1:这是迄今为止最好的答案;它解释了出了什么问题。 run1runningrun.sh 三个文件中没有一个实际上包含单词 run,因此您不会从 ls -l | grep run* 命令获得任何输出。事实上,ls -l 的输出完全被grep 忽略了;它仅在没有文件名参数时读取其标准输入,或者当这些参数之一是 -(破折号,全部独立)或名称之一,例如 /dev/stdin/dev/fd/0 是同义词用于标准输入。
  • @user3083195 我现在看到了混乱。 No match 消息实际上是由 shell 在找不到与您的 glob 模式匹配的文件名时发出的。 shell 打印grep: No match 表示您尝试使用文件名模式运行grep,但该文件名模式没有产生任何要运行的文件名,因此shell 实际上根本没有运行grep。当grep 搜索文件并且没有找到任何与您的正则表达式匹配的内容时,它只会安静地打印不输出并且不会产生任何错误消息。这有助于解释差异吗?
猜你喜欢
  • 1970-01-01
  • 2017-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多