OP 被标记为 bash
.
如果您正在使用 bash
并且不需要担心可移植性,那么几乎没有理由使用 test
(或 [
的习惯 [[
... ]]
(并且而不是 expr
或 let
,更喜欢 ((
... ))
进行算术评估。)
请参阅 条件构造 。
在 CLI 上, test
不会更改上下文 , 因此 \'globs\' ( *
) 将使用文件名扩展进行处理,并替换为所有匹配项的列表,这会生成过多的参数 test
.
在 中有很多方法可以检查字符串和文件 bash
,有些方法会重叠。正如评论中提到的, [[
和 case
构造都将使用通配符,而无需进行分词或路径名扩展。
鉴于 f=fofo.l
和 x=abcd
,
$: dotl(){ [[ $1 == *.l* ]] && echo match || echo nope; }
$: dotl $f
match
$: dotl $x
nope
$: dotl(){ case $1 in *.l*) echo match;; *) echo nope;; esac; }
$: dotl $f
match
$: dotl $x
nope
如果你更喜欢实际的正则表达式 -
$: dotl(){ [[ $1 =~ [.]l ]] && echo match || echo nope; }
$: dotl $f
match
$: dotl $x
nope
如果您需要可移植性,并且高性能不是主要关注点,那么有很多广泛可用的程序可供您进行测试 - 这 grep
是此类事情的通常选择。
$: dotl(){ echo $1 | if grep -q '[.]l'; then echo match; else echo nope; fi; }
$: dotl $f
match
$: dotl $x
nope
参数扩展 来做这样的“技巧” (尽管我一般不推荐这样做):
$: dotl(){ local tst=${1/#*.l*/}; echo "$1 contains ${tst:+NO }.l"; }
$: dotl fofo.l
fofo.l contains .l
$: dotl ooo.lala
ooo.lala contains .l
$: dotl abcd
abcd contains NO .l
也许这是一个 X/Y 问题 ,而您要问如何判断一个文件是否具有给定的字符串,因为您计划遍历所有文件并对每个文件执行某些操作(如果匹配)-所以您真正想要的是匹配的文件列表,而不是对每个文件进行测试。
为此,glob 可以一次性处理所有事情:
$: touch fofo.l ooo.lala abcd
$: echo *
abcd fofo.l ooo.lala
$: echo "Files with '.l':" *.l*
fofo.l ooo.lala
$: for f in *.l*; do echo ${f^^}; done
FOFO.L
OOO.LALA
再从另一个角度来看,也许查找表会有所帮助。
$: . <( lst=(*.l*); shopt -s patsub_replacement; echo "declare -A lookup=(${lst[@]//*/[&]=1})" )
$: declare -p lookup # lst inside is scoped to the subshell; use outside to keep
declare -A lookup=([ooo.lala]="1" [fofo.l]="1" )
$: echo "There are ${#lookup[@]} Files with '.l': ${!lookup[@]}"
There are 2 Files with '.l': ooo.lala fofo.l
$: for f in *; do [[ -n "${lookup[$f]}" ]] && echo "$f contains .l" || echo "$f does not contain .l"; done
abcd does not contain .l
fofo.l contains .l
ooo.lala contains .l
只需确保针对一些最奇怪和最不可能 实际 发生的用例来测试您选择的方法。文件名 可以 包含嵌入空格,甚至包括换行符、回车符和/或控制字符,如退格符、铃声或文件结尾标记。