Last updated on November 18, 2019
前言
各位读者好,看到本文标题你会想到什么?你觉得哪些用法才算是find命令的高级用法?
本文介绍的和你想到的一致吗?
本文重点介绍如何利用-exec
和xargs
命令实现find命令和其他命令的结合,进而向大家展示find命令的强大。
欢迎留言讨论
(一) find 命令-exec
和-ok
参数
有很多场景需要对查找到的文件进行进一步操作,比如批量对文件进行权限的更改,用户属性的更改以及对文件行数进行统计等等。
-exec
和-ok
参数可以实现这个需求。
比如下面这个查找所有txt文件并统计行数的需求。
find tmp_dir -name "*.txt" # 查找所有txt文件
tmp_dir/hello world.txt
tmp_dir/test2.txt
tmp_dir/test3.txt
tmp_dir/test1.txt
find tmp_dir -name "*.txt" -exec wc -l {} \; #查找文件并统计文件中行数
0 tmp_dir/hello world.txt
6 tmp_dir/test2.txt
0 tmp_dir/test3.txt
4 tmp_dir/test1.txt
通过这个例子我们可以看出 -exec的用法是在正常的find命令后 添加 -exec command {} \;
其中 {}
是配合-exec
参数的特殊字符串,{}会被find的结果即文件名所替换。
上条命令的执行结果就相当于分别执行了 wc -l tmp_dir/test2.txt
和wc -l tmp_dir/test1.txt
wc -l tmp_dir/test2.txt
wc -l tmp_dir/test1.txt
6 tmp_dir/test2.txt
4 tmp_dir/test1.txt
可以看到执行结果是相同的。-exec 的强大之处就是我们不用手动执行n次命令了,
可以批量对查找到的文件执行相应的操作。
此外 \;
这个参数可以对替换为+
。 那么二者的区别是什么呢?
find tmp_dir -name "*.txt" -exec wc -l {} +
0 tmp_dir/hello world.txt
6 tmp_dir/test2.txt
0 tmp_dir/test3.txt
4 tmp_dir/test1.txt
10 total
wc -l tmp_dir/test2.txt tmp_dir/test1.txt
6 tmp_dir/test2.txt
4 tmp_dir/test1.txt
10 total
通过例子我们可以看出,find tmp_dir -name "*.txt" -exec wc -l {} +
的执行结果
和wc -l tmp_dir/test2.txt tmp_dir/test1.txt
的执行结果是一样的。
其实 \;
表示针对查找到的每一个文件分别执行一次命令,单个文件名作为命令的参数,有多少个文件就执行多少次命令。
而+
表示把查找到的所有文件作为一个参数列表传给命令,对应命令只执行一次。
-ok
参数和 -exec
具有同样的功能,只不过-ok需要和用户交互,用户需要确认执行相应的命令
find tmp_dir -name "*.txt" -ok wc -l {} \; #统计文件中行数
执行结果如下图所示,用户需要输入y还是n来进行选择是否执行。
输入y执行命令:
输入n不执行命令
(二) xargs 命令
xargs 用法是:command | xargs
xargs命令可以对从stdin接收到的数据进行重新格式化转化为其他命令的参数
- 利用xargs把输入的多行数据转化成一行数据输出,现在有个example.txt其内容是这样的
cat example.txt
1 2 3 4 5 6
7 8 9 10
11 12
通过xargs 转化后其结果如下所示:
cat example.txt |xargs
1 2 3 4 5 6 7 8 9 10 11 12
- 利用xargs把单行数据转化成多行数据
cat example.txt |xargs -n 3
1 2 3
4 5 6
7 8 9
10 11 12
可以看到example.txt的文件第一行原本有6个数字,现在经过处理后输出的每行都有3个数字。
-n 表示每行有3个输出,默认以空格为分隔符。
xargs 可以用-d 指定输入的分割符,如果不指定的话默认以空格作为输入的分割符
结果如下
echo "splitXsplitXsplitXsplit" | xargs -d X
split split split split
echo "splitXsplitXsplitXsplit" | xargs -d X -n 2
split split
split split
- 利用xargs向其他命令提供参数
有一个脚本叫cecho.sh 脚本的作用就是在参数后面加上一个’#’并输出
bash ./cecho.sh arg1 arg2
arg1 arg2#
现在有这样一个场景: 我有一个文件args.txt,文件内容每一行是一个参数,有时我需要每次对命令(这里指cecho.sh)提供一个参数,
时我需要一次对命令提供2个参数,有时需要提供3个参数。该如何做呢?
args.txt 文件内容如下:
cat args.txt
arg1
arg2
arg3
对于上面所说的3种场景,可以分别用下面的命令实现
cat args.txt | xargs -n 1 bash ./cecho.sh
arg1#
arg2#
arg3#
cat args.txt | xargs -n 2 bash ./cecho.sh
arg1 arg2#
arg3#
cat args.txt | xargs bash ./cecho.sh # xargs不带-n 时会把所有输入准化成一行
arg1 arg2 arg3#
在上面这个例子中,我们直接把args.txt中的值传给了cecho.sh。但是在实际中,相应的值应该传给对应的参数选项(option)
即实际上cecho.sh的调用形式应该是这样的: ./cecho -p arg1 -l
我们希望达到这样的效果,
./cecho -p arg1 -l
./cecho -p arg2 -l
./cecho -p arg2 -l
那么通过cat args.txt | xargs -n 1 bash ./cecho.sh -p -l
是无法实现的,
其运行结果如下,我们需要把arg1 直接放在 -p 的后面。
cat args.txt | xargs -n 1 bash ./cecho.sh -p -l
-p -l arg1#
-p -l arg2#
-p -l arg3#
这时就要通过占位符来实现了。
cat args.txt | xargs -I {} bash ./cecho.sh -p {} -l
-p arg1 -l#
-p arg2 -l#
-p arg3 -l#
其中 -I {}
定义了替换字符串,{}
会被从标准输入中读到的实参值替代。
此外我们还可以看到,使用-I {}
时,我们并没有指定 -n 1
就实现了每次值传递一个参数,
这是因为当指定-I
时,命令会在一个循环中执行,有多少个参数,就执行多少次命令,每次命令执行时{}
都会被真正的参数代替。
(三) find和xargs的结合
两个使用场景:
(1)在写本文期间我创建了很多txt文件,那么最后我想批量删除
先来看看都有什么文件
find tmp_dir -name "*.txt"
tmp_dir/hello world.txt
tmp_dir/test2.txt
tmp_dir/test3.txt
tmp_dir/test1.txt
find tmp_dir -name "*.txt" -print | xargs rm -f
我们再来检查一样删除后的结果,发现"hello world.txt"并没有被删除
find tmp_dir -name "*.txt"
tmp_dir/hello world.txt
这是为什么呢?
默认情况下xargs
使用空格作为分割符,"hello world.txt"会被误分割为hello和world.txt。
因此我们可以指定find的输出的分隔符是什么。并且xargs也指定相应的分割符
find tmp_dir -name "*.txt" -print0 | xargs -0 rm -f
find tmp_dir -name "*.txt" -print0
ls tmp_dir
可以发现目前tmp_dir下的"hello world.txt" 文件被正确的删除了
Be First to Comment