![在“ls”命令中使用通配符查找仅包含大写字母的文件](https://linux22.com/image/117009/%E5%9C%A8%E2%80%9Cls%E2%80%9D%E5%91%BD%E4%BB%A4%E4%B8%AD%E4%BD%BF%E7%94%A8%E9%80%9A%E9%85%8D%E7%AC%A6%E6%9F%A5%E6%89%BE%E4%BB%85%E5%8C%85%E5%90%AB%E5%A4%A7%E5%86%99%E5%AD%97%E6%AF%8D%E7%9A%84%E6%96%87%E4%BB%B6.png)
因此,我一直在研究文件系统,并想知道是否列出/etc
名称中仅包含大写字母的文件。我命令
ls *[A-Z]*
但控制台也显示包含较低字符的文件。我只想使用ls
命令。控制台程序区域设置是否相关?
根本原因是什么?
答案1
[A-Z]
并不意味着大写。它表示从A
到 的字母Z
,其中可能包含小写字母。通常你应该使用[[:upper:]]
。 (即使没有 .,这也可以在 Bash 中工作extglob
。)
匹配哪些字符[A-Z]
取决于您的区域设置。
你已澄清您想要显示在任何地方至少包含大写字符的所有文件名 - 不仅是完全由大写字符组成的文件名 - 而且当您使用 时ls *[A-Z]*
,您会得到一些不包含大写字符的文件名任何其中的大写字符。
当您的语言环境的词典顺序穿插有大写和小写字母时(例如,AaBbCcDd...),就会发生这种情况。尽管您可以设置其他区域设置(例如,LC_ALL=C
),但最佳解决方案通常是编写专门匹配大写字母的模式。
哪些字符是大写字母不同区域设置之间也可能有所不同,但如果某些内容在您的区域设置中是大写字母,那么您可能希望将其包含在内。所以这可能是一个优点[[:upper:]]
而不是一个缺点。
代替使用[[:upper:]]
。
大多数 Bourne 风格的 shell(例如 Bash)都支持 glob 中的 POSIX 字符类。此命令将列出/etc
名称中至少有一个大写字母的条目:
ls -d /etc/*[[:upper:]]*
您获得的某些条目可能是目录。如果您想显示其内容而不仅仅是列出目录,那么您可以删除该-d
标志。您可能还想--
在模式之前放置一个标志,以防/etc
其中有以 开头的条目-
。但你可能不知道。 (在脚本中,您通常需要--
在此处使用。)
您可能不想要点文件,但如果您想要......
这不会显示以 开头的条目.
。通常你不想展示给他们看。如果您确实需要它们,大多数 shell 允许您编写一个也与它们匹配的 glob,或者配置 globbing 以默认包含它们。.
在 Bash 中自动包含前导条目的选项是dotglob
,并且可以使用 启用它shopt -s dotglob
。对于其他外壳请参见
。或者你可以简单地为它们编写第二个 glob:
ls -d /etc/*[[:upper:]]* /etc/.*[[:upper:]]*
大多数流行的 Bourne 风格 shell 支持大括号扩展,因此您可以以更少的重复编写得更紧凑:
ls -d /etc/{,.}*[[:upper:]]*
在包括 Bash 在内的大多数 shell 中,当您编写两个单独的 glob 时,如果其中一个没有展开,您将收到一条错误消息 - 因为大多数 shell 中的默认行为是不展开它。但ls
仍会显示与另一个匹配的条目。但正如斯特凡·查泽拉斯(Stéphane Chazelas)指出的,在一些 shell 中,包括非常流行的 Zsh,整个命令会失败并且ls
永远不会运行。如果您以交互方式使用 shell,这并不是真正有害,因为您可以修改命令并再次运行它,但这种结构不适合可移植脚本。如果您设置了 shell 选项,Bash 也会以这种方式运行failglob
。
为此,您不需要扩展通配符。
在 Bash 中,您不需要启用扩展通配符即可在通配符模式中使用 POSIX 字符类。在我的 Bash 4.3.48 系统上:
ek@Io:~$ shopt extglob
extglob off
ek@Io:~$ ls -d /etc/*[[:upper:]]*
/etc/ConsoleKit /etc/LatexMk /etc/ODBCDataSources /etc/UPower
/etc/ImageMagick-6 /etc/NetworkManager /etc/rcS.d /etc/X11
但你确实需要它来匹配文件名仅有的大写字母。
你什么做如果您想匹配包含以下内容的文件名,则需要扩展通配符仅有的大写字母。然后你可以使用+([[:upper:]])
or *([[:upper:]])
,这些都是扩展的全局变量。
如果您使用的是 Bash,请参阅本文,本指南,3.5.8.1 模式匹配在里面GNU Bash 手册了解详情。也可以看看斯特凡·查泽拉斯的回答。
答案2
对于仅由大写字母组成的文件名。
(如FOO
, ÉTÉ
, ΛΈΞΗ
;不同于FOO.BAR
, ÉTÉ
(其后É
跟E
U+0301 结合锐音符号 1))
与ksh
或zsh -o kshglob -o nobareglobqual
或bash -O extglob
:
ls -d +([[:upper:]])
With zsh -o extendedglob
(你宁愿使用它而不是kshglob
):
ls -d [[:upper:]]#
或者使用 GNU ls
(假设文件名仅包含有效字符):
ls --ignore='*[^[:upper:]]*'
或者用find
代替ls
(这里只是输出它的参数,我希望你想使用像-l
它这样有用的选项):
find . ! -name . -prune -name '*' ! -name '*[^[:upper:]]*'
(这-name '*'
是为了过滤掉包含无效字符的文件名,下一个! -name
将无法过滤掉这些文件名(find
至少在某些实现中))
对于不带小写字母的文件名
(但仍然允许使用非字母,如 in ABC.TXT
),其中ksh
:
(FIGNORE='@(.|..|*[[:lower:]]*)'; ls -d -- *)
与bash -O dotglob -O extglob
或zsh -o kshglob -o dotglob -o nobareglobqual
:
ls -d -- !(*[[:lower:]]*)
或者zsh -o extendedglob
:
ls -d -- ^*[[:lower:]]*(D)
或者使用 GNU ls
(假设文件名仅包含有效字符):
ls -A --ignore='*[[:lower:]]*' --ignore='.*[[:lower:]]*'
(事实上,--ignore='.*[[:lower:]]*'
需要额外的东西对我来说似乎是一个错误)
和find
:
find . ! -name . -prune -name '*' ! -name '*[[:lower:]]*'
(对于某些find
实现,不包括具有无效字符的文件名,即使有效字符都不是小写字符)。
对于至少包含一个大写字母的文件名:
(像Foo.bar
,,.Été.txt
不像123.6
,foo.bar
)
使用zsh -o dotglob
or bash -O dotglob
(dotglob
包含名称以 开头的文件.
):
ls -d -- *[[:upper:]]*
和find
:
find . ! -name . -prune -name '*[[:upper:]]*'
(对于某些find
实现,不包括具有无效字符的文件名,即使某些有效字符是大写字符)
1 要允许使用 组合字符,zsh -o pcrematch
您可以使用类似 perl 的正则表达式,利用 Unicode 字符属性:
ls -d -- *(e@'[[ $REPLY =~ "^(?>\p{Lu}\pM*)*$" ]]'@)
答案3
请原谅我之前的回答,我还没喝咖啡。
我不确定是否仅使用 ls 来执行此操作。但是,这里还有另一个 grep 可以解决这个问题:
LS | egrep ^[^a-z0-9]*$
答案4
为什么你只想使用 ls?您可以简单地使用 find 来代替:
find -regex './[A-Z]+'
编辑:
根据man 7 glob
:
通配符匹配
如果字符串包含字符“?”、“*”或“[”之一,则该字符串是通配符模式。通配符是将通配符模式扩展为与该模式匹配的路径名列表的操作。匹配定义为:A '?' (不在括号之间)匹配任何单个字符。
'*'(不在方括号之间)匹配任何字符串,包括空字符串。
字符类
表达式“[...]”,其中前导“[”之后的第一个字符不是“!”匹配单个字符,即方括号括起来的任何字符。
常用表达
请注意,通配符模式不是正则表达式,尽管它们有点相似。首先,它们匹配文件名,而不是文本,其次,约定不一样:例如,在正则表达式中“*”表示前面的内容的零个或多个副本。现在正则表达式具有括号表达式,其中否定由“^”表示,POSIX 已声明通配符模式“[^...]”的效果未定义。
如果您想使用 ls 您必须记住 bash 不会以与find -regexp
or相同的方式翻译您的“*” grep
。 *[AZ]* 将尝试匹配任何字符串,后跟大写字母,后跟任何字符串,所以基本上是任何字符串。