[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ]
描述:上一章,我们学习了Linux中查找搜寻文件或目录的相关命令,此章我们学习常常与find命令联合使用,以及在Shell脚本中常用的参数替换 xargs 命令进行实践学习,从而实现更加强大的参数传递和多进程并行执行Linux命令或脚本等
描述:xargs(eXtended ARGuments
)工具是给命令传递参数的一个过滤器,也是组合多个命令的一个工具。
由于很多命令不支持|管道来传递参数,此时就需要 xargs 命令的帮助,它可以读入stdin 的数据,并将格式化(空格符、回车符进行分隔)后的数据作为命令的参数,还可以将单行或多行文本输入转换为其他格式,例如,多行变单行以及单行变多行,后续实践我们会介绍到。
另外,许多命令不能接受过多的参数而导致命令执行失败,此时可以使用xargs 命令解决该问题。例如,使用 rm 命令删除百万级文件时会提示参数过多,这时可使用 find
命令 或 ls
命令 与 xargs
命令联用进行删除。。
工具功能:
将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据。
将单行或多行文本输入转换为其他格式,例如多行变单行,单行变多行。
默认命令是echo 意味着通过管道传递给 xargs 的输入将会包含换行和空白,不过通过 xargs 的处理,换行和空白将被空格取代。
它能够捕获一个命令的输出,然后传递给另外一个命令,
语法参数:
# 用法
command | xargs [OPTION]... COMMAND [INITIAL-ARGS]..
# 常用参数
-0 # 将NULL作为定界符。
-t # 表示先打印命令,然后再执行。
-a FILE # 指定一个参数文件,而不是从标准输入中读取。
-n NUM # 指定每行显示多少NUM列;
-L num # 从标准输入一次读取 num 行送给 command 命令。
-l # 类似于-L,但如果未指定MAX-LINES,则默认为最多一个非空白输入行
-d '定界字符': # 指定一个定界符注意必须是单字符;
-x, --exit # 如果超过大小(参见-s),则退出。
-r no-run-if-empty # 当xargs的输入为空的时候则停止xargs,不用再去执行了。
-I R # 指定一个替换字符串{},这个字符串再xargs扩展时会被替换掉,当-I与xargx联合使用的时候每一个参数命令都会被执行一次,类似于find的-ok/-exec选项
-i, --replace[=R] # 看linux支持了,将xargs的每项名称,一般是一行一行赋值给 {},可以用 {} 代替。
-n, --max-args=MAX-ARGS # 每个命令最多使用MAX-ARGS参数行
-P, --max-procs=MAX-PROCS # 一次运行最多的max-procs进程
-p, --interactive # 批量运行命令前交互式提示
-s, --max-chars=MAX-CHARS # 最多将命令限制为MAX-CHARS
-o, --open-tty # 在执行命令之前,在子进程中将stdin重新打开为/dev/tty;有助于运行
使用示例:
首先,定义一个测试用例文件,内有多行文本数据:
$ cat test.txt
a b c d e f
g h i j k l
m n o p q r
s t u v w x y z
# 示例1.默认情况下的多行变单行处理
cat test.txt | xargs
# a b c d e f g h i j k l m n o p q r s t u v w x y z
# 示例2.指定每行显示3个参数
cat test.txt | xargs -n3
# a b c
# d e f
# g h i
# 示例3.指定每行显示4、6个参数
cat test.txt | xargs -n4
cat test.txt | xargs -n6
# 示例4.每次处理 5 个文件,到/backup 目录下
find . -name "*.jpg" | xargs -n 5 cp -t /backup/
ls /backup/
# 10.jpg 1.jpg 2.jpg 3.jpg 4.jpg 5.jpg 6.jpg 7.jpg 8.jpg 9.jpg
# 示例5.每次处理 10 个文件,移动到/destination 目录下
find /path/to/dir -name "*.jpg" | xargs -n 10 mv -t /destination/示例6.批量添加多个用户到linux中
echo user{1..10} | xargs -n1 useradd
weiyigeek.top-指定xargs处理参数后显示的列数
# 默认情况下,xargs 是以换行符,或空格作为分隔符
echo -e "dir1\ndir2\ndir3" | xargs
# dir1 dir2 dir3
echo "nameXWeiyiGeekXnameX全栈工程师修炼指南" | xargs -dX
# name WeiyiGeek name 全栈工程师修炼指南
# 显示成为两列,这是我们需要的格式
echo "nameXWeiyiGeekXnameX全栈工程师修炼指南" | xargs -dX -n2
# name WeiyiGeek
# name 全栈工程师修炼指南
echo "file1.txt file2.txt file3.txt" | xargs -p rm
# rm file1.txt file2.txt file3.txt ?...y
echo "file1 file2 file3" | xargs -I {} mv {} {}.bak
# 示例1.复制所有图片文件到 /data/images/ 目录下,注意反斜杠
mkdir -vp /data/images/
ls *.png *.jpg *.gif | xargs -n1 -I {} cp {} /data/images/
# 示例2.查找当前目录下所有不可修改的文件 (对于入侵监测的时候可使用)
find . | xargs -I {} lsattr -a {} 2>/dev/null | grep '^----i'
# 例1,同时压缩多个文件:
find . -name "*.log" | xargs -P 4 gzip
# 例2, 指定并行进程数为256,批量执行文件上传操作
thread_num=256
ls | xargs -n 1 -I {} -P ${thread_num} sh -c "/usr/binfs_upload_file /etcfs/client.conf {}"
ls -I '*.yml' | xargs -I {} rm -rf {}
# 例3.批量并行执行test.txt文件中,复制文件到到指定目录
cat test.txt <<'EOF'
cp ./0101/123456789.JPG ../2023/0101/123456789.jpg
cp ./0102/123456789.JPG ../2023/0102/123456789.jpg
cp ./0103/123456789.JPG ../2023/0103/123456789.jpg
EOF
cat test.txt | xargs -n 1 -I {} -P 256 sh -c "{}"
# 例4.并发执行多个进程进行文件下载
seq 100 | xargs -i -P10 wget -P /data http://share.weiyigeek.top/{}.zip
# 例5.并行下载B站视频
yum install python3-pip -y
pip3 install you-getseq 1 100 | xargs -i -P3 you-get https://www.bilibili.com/video/BV19D4y1D7UX?p={}
# 如果文件名中包含空格或特殊字符,可以使用 -print0 和 -0 选项,让参数以NULL分隔
find . -name "*.log" -print0 | xargs -0
# ./audit/audit.log ./sssd/sssd_implicit_files.log ./sssd/sssd_nss.log
# 或者使用 --null 选项,将换行符或空格作为文件名分隔符
find . -type f -name "*.log" -print0 | xargs -n1 --null
# ./audit/audit.log ./sssd/sssd_implicit_files.log ./sssd/sssd_nss.log
# 例1.删除某个目录下的所有 .tmp 文件
# 使用用 rm 删除太多的文件时候,可能得到一个错误信息:/bin/rm Argument list too long. 用xargs解决此问题。
find /dir -name "*.tmp" | xargs rm -f
# 例2.查找当前目录下所有 .txt 文件并统计它们的行数:
find . -name "*.txt" | xargs wc -l
# 例3.以 NULL 字符作为换行符,并以三列显示
find . -type f -name "*.log" -print0 | xargs -0 -n3
# ./tuned/tuned.log ./audit/audit.log ./anaconda/anaconda.log
# ./anaconda/X.log ./anaconda/program.log ./anaconda/packaging.log
# ./anaconda/storage.log ./anaconda/ifcfg.log ./anaconda/ks-script-ECgRju.log
# 例4.统计文件信息,统计一个源代码目录中所有php文件的行数
find . -type f -name "*.php" -print0 | xargs -0 wc -l
# 例5,查找当前目录下所有的jpg 文件,并且压缩它们
find . -type f -name "*.jpg" -print | xargs tar -czvf images.tar.gz
# 例6. 查询带有 SUID SHID SBIT 等权限的文件
find /bin -perm -7000 | xargs ls -Sl
# 假设一个命令为 weiyigeek.sh 和一个保存参数的文件arg.txt:
# weiyigeek.sh 脚本命令内容,打印出所有参数
tee weiyigeek.sh <<'EOF'
#!/bin/bash
echo $*
EOF
# arg.txt 文件内容:
aaa
bbb
ccc
# 可以利用这个来更改ip文本以及脚本参数的传入
cat arg.txt | xargs -I {} ./weiyigeek.sh -p {} -l
cat arg.txt | xargs -I {} echo $* "-p123" {}"- l123"
-p aaa -l
-p bbb -l
-p ccc -l
# 方式1.使用xargs格式化之后输出
cat url.txt | xargs -I {} echo $* "Url:"{}"/admin/web.jsp"
# 也可以使用awk一步搞定,后续我们也要介绍文件处理三剑客之一的命令
awk '{print "Url:"$1"/admin/web.jsp"}' url.txt
# Url:http://demo1.weiyigeek.top/admin/web.jsp
# Url:http://demo2.weiyigeek.top/admin/web.jsp
# Url:http://demo3.weiyigeek.top/admin/web.jsp
weiyigeek.top-使用xargs格式化之后输出
# 例1.查找所有 .log 文件中包含 "Error" 的行,并对结果进行排序和去重,最后统计每个唯一行的出现次数
find /path/to/dir -name "*.log" | xargs grep "Error" | sort | uniq -c
# 假2,有一个文件包含了很多你希望下载的URL,你能够使用xargs下载所有链接
cat url-list.txt | xargs -P10 wget -c