blog-web/source/_posts/linux/xargs命令.md
结发受长生 7c165816f4 xargs命令
2019-08-24 01:28:38 +08:00

161 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: xargs命令
date: 2019-8-23 23:05:33
tags:
- linux
categories:
- linux
---
`xargs`命令的作用可以概括为将标准输入转化为命令行参数
<!-- more -->
### 标准输入与管道符
Linux下有些命令是可以接受标准输入的
例如下面这些命令
+ `cat` 查看文件内容
+ `sort` 对文件内容的行进行排序
+ `uniq` 报告或忽略文件中重复的行必须先进行排序所以常与sort配合使用
+ `grep` 根据规则找出匹配到的行
+ `wc` 获得文件中换行符,字,和字节个数
+ `head` 输出文件的开头部分
+ `tail` 输出文件的结尾部分
+ `tee` 从标准输入读取数据,并同时写到标准输出和文件
#### 标准输入的重定向
我们以sort命令为例
所有可以接受标准输入的默认标准输入指向都是**控制台输入**
如果直接执行sort
![默认标准输入](/images/linux/io/默认标准输入.png)
如果我们把这些内容写到**1.txt**这个文件当中
就可以执行
```bash
sort 1.txt
# 或者
sort < 1.txt
```
需要注意的是这两种写法虽然效果一样,但是含义是不同的
前者是给sort命令的传参后者则是输入重定向
查看sort命令的帮助可以看到相关说明
![sort help](/images/linux/io/sort_help.png)
> 如果没有指定文件,则从标准输入读取
所以前者并没有改变标准输入的指向,只是因为指定了文件,该命令本身不再从标准输入读取
后者并没有指定文件,而是改变了标准输入的指向
#### 管道符
Linux当中的`|`称为管道符,使用方式为
```
command1 | command2
```
它的作用是把command1的标准输出作为command2的标准输入相当于对command2做了标准输入的重定向
可以利用它完成较为复杂的链式处理
比如
```bash
tail < 1.log | sort | uniq -d -c | grep 'ab'
```
表示的含义是
1. 读取1.log文件的最后10行
2. 将这10行的内容作为sort的标准输入
3. 将排序后的内容作为uniq的标准输入找到其中重复出现的行以及出现的次数
4. 重复出现的行内容作为grep的标准输入从中筛选包含字符串ab行
### xargs命令
使用管道符进行链式处理非常方便,但是能够接受标准输入的命令其实很少
大多数命令都不接受,只能接收命令行的传参
比如常见的`ls`命令,用来查看目录下的文件,它就不接受标准输入
例如现在有**apache2**和**php-apache**这两个目录,我们要列出这两个目录里面各自包含的文件
先创建好一个input.txt文件内容就是
```
apache2 php-apache
```
命令写法
```bash
# 当然可以这样做,常规的传参方式
ls apache2 php-apache
# 如果要从其他来源读取要列出内容的目录呢
ls < input.txt #这样是无效的
cat input.txt | ls #这样与上面的是在做一样的事,同样无效
# 必须使用xargs把标准输出转化为传参
cat input.txt | xargs ls
```
管道符把标准输出作为xargs的标准输入
xargs则把标准输入转化为了命令行参数传递给后面真正要执行的命令在这里就是ls
> 如果xargs后面没有跟任何命令那么就代表跟的是echo
echo命令的作用就是把接收到的参数输出到标准输出
#### 单独使用
xargs虽然有这些作用但是它本身仍然是个可以接受标准输入的命令
如果没有进行标准输入的重定向 (`<`或者`|`)
那么它的标准输入就是指向控制台后面相当于跟着echo
单独执行xargs的表现也就可以理解了
```bash
root@ubuntu:~$ xargs
abcd #Ctrl+D
abcd
```
命令行会等待用户输入,并且把这些输入直接输出
如果跟上了其他命令呢
```bash
root@ubuntu:~$ xargs find -name
*.txt #Ctrl+D
./input.txt
./1.txt
```
执行后会等待用户输入Ctrl+D结束输入
把这些输入的内容作为参数提供给find命令
所以相当于执行`find -name *.txt`
### 其他使用技巧
#### 与find的搭配使用
如果我们要删除7天之前修改的文件
由于rm命令只能按照文件名匹配find则具备多种方式的文件查找
所以两者搭配使用更加方便
先熟悉一下find命令如何按时间查找文件
|+n|n|-n|
|--|-|--|
|(n+1)\*24H前|(n+1)\*24H ~ n\*24H之间|n*24H以内|
+ `[a|c|m]min` \[最后访问|最后状态修改|最后内容修改\]min(单位是分钟)
+ `[a|c|m]time` \[最后访问|最后状态修改|最后内容修改\]time(单位是天)
```bash
# 查找当前目录7天之前修改的文件并且作为rm的参数执行删除
find ./ -mtime +6 | xargs rm
```
上面的写法有个问题就是xargs是使用**空白**作为参数的分隔的,但是文件名可能包含空格
应该使用下面的写法
```bash
find ./ -mtime +6 -print0 | xargs -0 rm
```
`-print0`提供给find命令代表输出的文件列表以null作为分隔
`-0`提供给xargs命令代表以null作为分隔来切分参数列表
#### -p 和 -t 参数
过长的命令串联有种难以掌控的感觉,如果出现了失误可能造成无法挽回的结果
`-t`参数可以在执行xargs后面命令之前打印出要执行的内容
`-p`参数会等待用户确认在用户输入y大小写皆可后再执行
#### -L 参数
xargs把标准输入转化为参数提供给后面的命令执行默认情况下是执行一次的
如果我们要把每一行的输出循环执行呢
这就需要用到`-L`参数了,后面跟上行数,代表把几行作为一组参数传递给后面的命令执行一次
![xargs循环执行](/images/linux/io/xargs循环执行.png)
<del>要问带\n的字符串为啥这样写我只能说shell的晦涩之处不止于此</del>
可以看到前一次执行了`ls -l -h`
后一次分别执行了`ls -l``ls -h`