我在这里陷入了一个非常微不足道的问题:如何使*
bash 中的符号有意义零个或多个,就像它在工具中所做的那样sed
?
例如,ak*
应该匹配名称完全由a
后面跟着零个或多个k
s 组成的任何文件。它的扩展将包括a
、ak
、akk
和akkk
,但不包括akc
。
我已经unsetopt sh_glob
在 zsh 和set -o noglob
bash 中尝试过;他们没有产生预期的行为。
答案1
除了ksh93
,常用的 shell 都没有与 sed、awk 等语法相同的正则表达式可用于匹配文件。
Ksh93、bash 和 zsh 具有不同语法的正则表达式,并且向后兼容 glob:
?
匹配任何单个字符(就像.
通常的正则表达式语法一样)[…]
以几乎相同的方式匹配字符集*(FOO)
匹配任意数量的出现FOO
(就像通常的正则表达式语法一样)(FOO)*
- 同样匹配一次或多次出现,并匹配零次或一次出现
+(FOO)
?(FOO)
@(FOO|BAR)
匹配FOO
或者BAR
- 匹配适用于整个字符串,而不是子字符串;如果你想要一个子字符串,请放在
*
开头和结尾
shopt -s extglob
此语法需要在 bash 和zsh 中激活setopt ksh_glob
。所以在 bash 中你会写
shopt -s extglob
ls a*(k)
也可以看看为什么我的正则表达式在 X 中有效但在 Y 中无效?
=~
Ksh93、zsh 和 bash 可以使用构造的运算符在字符串上与扩展正则表达式(基本上是 awk 的语法)进行正则表达式匹配[[ … ]]
。虽然这对于列出文件来说并不方便,但如果您确实想要它,这是可以完成的。
shopt -s dotglob # <<< include dot files, for bash
setopt globdots # <<< include dot files, for zsh
FIGNORE='@(.|..)' # <<< include dot files, for ksh
for x in *; do
if [[ $x =~ ^ak*$ ]]; then
…
fi
done
答案2
ls ak{k,}
将显示以 开头的文件,ak
后跟另一个文件k
或不显示任何文件。
$ touch ak akk akc
$ ls -l ak{k,}
-rw-rw-r-- 1 cas cas 0 Oct 27 10:30 ak
-rw-rw-r-- 1 cas cas 0 Oct 27 10:30 akk
glob 不是正则表达式,但它们不仅仅是*
and ?
。
如果你想使用正则表达式来查找匹配的文件名,可以使用以下find
命令:
$ find . -maxdepth 1 -type f -regex './ak+$'
./ak
./akk
该-maxdepth 1
选项将搜索限制为仅当前目录(不会搜索子目录)
如果您想要不区分大小写的搜索,请使用-iregex
而不是-regex
.
有多种方法可以使用find
在其他命令中找到的文件。例如:
find . -maxdepth 1 -type f -regex './ak+$' -ls
find . -maxdepth 1 -type f -regex './ak+$' -exec ls -ld {} +
find . -maxdepth 1 -type f -regex './ak+$' -print0 | xargs -0r ls -ld
ls -ld $(find . -maxdepth 1 -type f -regex './ak+$')
最后一个示例容易出现各种故障模式,包括 1. 不处理文件名中的空格等,2. 命令行长度限制。不建议。
答案3
您可以使用的语法bash
是:
ls a+(k)
这取决于启用的bash
shopt
shell 选项。extglob
在 Ubuntu 14.04 GNU/Linux 上,这似乎是默认启用的。
它是这样工作的:
$ shopt extglob
extglob on
$ ls
ak akc akd akk akkk akkkk
$ ls a+(k)
ak akk akkk akkkk
$ shopt -u extglob
$ shopt extglob
extglob off
$ ls a+(k)
bash: syntax error near unexpected token `('
$
来自 Bash 手册:
+(模式列表)
匹配给定模式的一次或多次出现。
模式列表是由“|”分隔的一个或多个模式的列表。
请参阅 Bash 手册:https://www.gnu.org/software/bash/manual/bash.html#Pattern-Matching。
答案4
根据外壳的一些选项:
$ touch a akk aka
$ ksh -c 'echo a*(k)'
a akk
$ zsh -o kshglob -o nobareglobqual -c 'echo a*(k)'
a akk
(nobareglobqual
此处尾随(k)
不被视为全局限定符)
$ bash -O extglob -c 'echo a*(k)'
a akk
$ zsh -o extendedglob -c 'echo ak#'
a akk
zsh
's#
相当于 regexp *
。
ksh93
还可以在其 glob 中使用多种类型的正则表达式:
$ ksh93 -c 'echo ~(E:ak*)' # extended RE
a akk
$ ksh93 -c 'echo ~(P:ak*)' # perl-like RE
a akk
$ ksh93 -c 'echo ~(X:ak*)' # AT&T augmented RE
a akk
$ ksh93 -c 'echo @(~(E)ak*)' # alternative syntax
a akk