刚刚在执行find搜索命令时,报错了。。
$ find ./ -maxdepth 1 -type f -name *.trace find: paths must precede expression: eEEProIfconfig.trace Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
网上查了下,原来是在使用正则搜索多个文件时,正则PATTERN表达式需要加上引号(单引号和双引号都可以)。
$ find ./ -maxdepth 1 -type f -name "*.trace" ./1.trace ./2.trace ./3.trace
其间网上看到这么两条指令:
$find /data/ -type f -name"*.txt" -exec cp {} /tmp \; $find /var/www/ -name file -exec cp {}{,.bak} \; 递归备份文件
对其中cp指令后面的空白大括号
比较疑惑。带着疑问网上搜索了下,得知{}大括号里的内容为find命令找到的结果
。
@astrotycoon 的《bash之花括号展开(brace expansion)》这篇博文详细介绍了bash中花括号(大括号)的扩展。
其中下图非常有意思,展示了bash shell的扩展顺序:
回到花括号扩展的问题上来,
花括号展开的定义(brace expansion)
花括号扩展有时在别的书籍中也被称为大括号扩展,是可以让bash生成任意字符串的一种扩展功能。它与后面会提到的“路径扩展”非常相似,唯一不同的是生成的字符串可以是不存在的路径或者文件名。
在bash中,花括号扩展在诸多扩展中的优先级最高,因此像类似于echo {a,b}$PATH的语句在完成花括号扩展之后的结果应该为a$PATH和 b$PATH,而对PATH环境变量的扩展需要到后续的“参数和变量扩展”阶段才开始。
花括号扩展的两种格式
第一类格式为:
preamble+{string1,string2,...,stringN}+postscript
左右的花括号是必须的,中间的字符串列表分别由逗号隔开,注意逗号前后不能有空格,如果string中有空格,则需要用单引号或者双引号括起来。
bash在实际扩展时,会将preamble和花括号种的所有字符串(按照从左到右的顺序)相连,最后分别加上postscript。
此外,花括号中间至少有一个逗号,否则bash不会认为这是括号扩展,例如echo {money}就只会输出{money},想要输出money,需要改为echo {money,},如下:
$echo {money}
{money}
$echo {money,}
money
$ echo sp{el,il,al}l
spell spill spall
$ echo sp{el,al}l //al之前有空格,则原样输出
sp{el,al}l
第二类格式为:
preamble+{<START>..<END>[..<INCR>]}+postscript
其中<START>..<END>组合而成的表达式术语叫做序列表达式(sequence expression),表示一个特定的范围。当<START>和<END>是数字时,代表的是数字范围;当<START>和<END>是单个字母时,代表的是字符范围(默认LC_ALL字符排序)。<START>和<END>必须同为数字或者字母,否则bash不认为是花括号扩展,而是原样输出。
其中的<INCR>
是可选的,代表的是区间范围的递增数,它必须是数字;如果不指定<INCR>
,那么默认是1或者是-1,具体是1还是-1,要看前面区间范围是递增的还是递减的。例如:
$ echo {0..10..2}
0 2 4 6 8 10
另外,当和是数字时,我们可以通过在数字前面加0来使输出结果的长度保持一致,例如:
$ echo {1..10}
1 2 3 4 5 6 7 8 9 10
$ echo {01..10}
01 02 03 04 05 06 07 08 09 10
$ echo {001..10}
001 002 003 004 005 006 007 008 009 010
下面再举几个例子
例子1:
//将find搜索结果来填充空白大括号
$find /data/ -type f -name"*.txt" -exec cp {} /tmp \;
//将/data/目录下的所有.txt文件复制到/tmp/目录下
注意,这条指令最后的
; 冒号
是必须要有的。
例子2:
$cp filename{,.bak}
//注意花括号边并没有空格,否则就不是扩展了,变成拷贝为{,.bak}文件了。
//这个命令是用来把filename备份成filename.bak,等同于命令
$cp filename filename.bak
例子3:
$touch file{1,2,3,4}.txt
$ls
file1.txt file2.txt file3.txt file4.txt