锚只能与 grep 一起使用还是可以与其他命令一起使用?
例如:
ls -l ^cat
Run Code Online (Sandbox Code Playgroud)
Dop*_*oti 18
诸如^
和 之类的正则表达式锚$
只能由实现正则表达式的工具解析。 ls
不是这样的工具,所以不,它不能使用它们。但是,从 shell 调用的任何二进制文件都可以使用 shell globbing,这是一种更简单但功能较弱的基于通配符的搜索机制。
例如,对于名称以 cat 开头的所有文件的列表:
$ ls cat* # lists all files with names which start with 'cat'
$ ls *dog # lists all files with names which end with 'dog'
$ ls d*y # Lists all files which names which start with 'd' and end
with 'y', e. g. 'donkey'
$ ls p?g # Lists all files which start with 'p', have one additional
character, and end with 'g', e. g. 'pig' and 'pug'
Run Code Online (Sandbox Code Playgroud)
出于通配目的,*
表示“零个或多个字符”;while 的?
意思是“恰好一个字符”。
Bas*_*tch 11
该/bin/ls
程序 - 就像任何其他程序一样 - 不处理*
模式。Globbing是由unix shell完成的,而不是由它们正在运行的程序完成的。让我解释一下。
该ls
程序(它有几个是自由软件的实现,比如来自 GNU coreutils包的实现,所以可以随意研究它的源代码)获取一个字符串序列(作为其 main
函数的第二个参数),这些字符串已经被你的 shell扩展了(经常bash
)。这不是特定于 的ls
,对于由您的 shell 启动的每个程序都是如此(通常通过使用您的PATH)。
例如,在包含a.c
, a.o
, b.c
, d.c
,e.h
文件的目录中,ls *.c
命令被shell扩展为ls a.c b.c d.c
so(在这种情况下)ls
得到 4 个参数:第一个(索引 0)是ls
,第二个(索引 1)是a.c
等等。 ..,第 4个(索引 3 的)是d.c
. 所以ls
程序永远不会看到 *.c
,shell 是execve(2) -用四个参数对其进行处理。由您的 shell 完成的程序参数扩展称为globbing。阅读glob(7)并了解IFS
shell 变量的作用。
(请注意,在某些情况下,像您这样的启动文件$HOME/.bashrc
可能会定义ls
为某个别名;然后替换ls
为\ls
orcommand ls
或/bin/ls
以避免此类别名扩展(后两者也可用于规避ls
重新定义为函数))
了解扩展发生的一个非常有用的技巧是首先使用shell的自动完成功能(例如使用您的TAB密钥),或者将命令(在您的情况下ls
)替换为echo
.
所以你真正想要的是一个带有扩展 globbing 的 shell。你可以找到几个,你可以编写自己的 shell 来做到这一点:
scsh具有非常不同的扩展(您可以在 Scheme 中对其进行编码)
或者调整现有的 shell(大多数是免费软件,您可以研究其源代码)以满足您的需要,或者编写您自己的 shell。
FWIW,sash
是一个非常简单和小巧的外壳(有点错误),其源代码易于阅读。
对于像bash这样的 Posix shell , - 以及像fish这样的其他shell - 您可以使用命令替换,例如使用find(1)(或者甚至一些ls
管道进入 some grep
,就像ls -l $(ls | grep '^foo')
这有点无用并且在某些情况下不起作用,例如带有空格或换行符的文件名,因为与ls -l foo*
)相同。
一些命令会使用一些(通常引用)参数或数据进行通配,例如find(1);你可以编写这样的程序,例如使用glob(3)或wordexp(3)。顺便说一句,您也可以在程序中使用正则表达式(由grep(1)等使用),以及regex(3)函数。
请注意,编写自己的 shell 是一项非常有趣的练习,我强烈建议您做一次。您需要学习如何使用syscalls(2),例如通过阅读诸如Advanced Linux Programming 之类的书,并实现您自己的通配符。和理解(的帮助下strace的(1) )什么电话系统是由一些贝壳做是值得的了。
实际上,如果ls ^cat
对您来说意味着列出名称以cat
您开头的所有文件,则只需ls cat*
在 shell 中键入命令即可。
顺便说一句,我真的更喜欢zsh
作为我的交互式shell(因为恕我直言,它的自动完成功能更好,并且它的扩展扩展非常有用),但这是一个品味问题,所以 YMMV。但是您可以尝试一下(如果您采用它,请使用chsh(1)更改您的登录外壳)。
最后,我建议避免在您自己的文件名中使用空格(以及换行符和控制字符以及大多数标点符号)(因此只需使用拉丁字母和数字、点.
、百分比%
、下划线_
、加号+
、非初始破折号-
或波浪号~
...),但是在编写供其他人普遍使用的 shell 脚本时,请考虑带有空格和奇怪字符的文件名。使用"$@"
在这样的脚本是那么好。
附注。在 Windows(我不知道)上,据传情况有所不同,通配符将由一些启动代码 à la crt0或可能在您的main
. 您可以阅读操作系统:三个简单的部分以获得更广阔的视野。
正如其他人所解释的,ls
不提供对正则表达式的支持。但是,可以使用 GNU 列出与某个正则表达式匹配的文件find
,如下所示。
首先,您可以使用以下ls
操作:
find * -maxdepth 0 -regex "ANY_REGEX" -ls
Run Code Online (Sandbox Code Playgroud)
您还可以使用该-exec
操作,它允许您使用任何命令:
find * -maxdepth 0 -regex "ANY_REGEX" -exec ls -la {} \+
Run Code Online (Sandbox Code Playgroud)
最后,您可以find
与结合xargs
,例如像这样:
find * -regex "ANY_REGEX" -print0 | xargs -0 ls -la
Run Code Online (Sandbox Code Playgroud)
默认情况下,find
将搜索所有子目录,这就是为什么要复制 的行为ls
,我添加了过滤器-maxdepth 0
。
行动-print0
中find
,期权-0
的xargs
最后一个例子是必要的处理包含空格的文件名。感谢@ilkkachu 指出。