diff --git a/images/linux/io/sort_help.png b/images/linux/io/sort_help.png new file mode 100644 index 0000000..4a8a68b Binary files /dev/null and b/images/linux/io/sort_help.png differ diff --git a/images/linux/io/xargs循环执行.png b/images/linux/io/xargs循环执行.png new file mode 100644 index 0000000..cacb0a3 Binary files /dev/null and b/images/linux/io/xargs循环执行.png differ diff --git a/images/linux/io/默认标准输入.png b/images/linux/io/默认标准输入.png new file mode 100644 index 0000000..dd2f92b Binary files /dev/null and b/images/linux/io/默认标准输入.png differ diff --git a/source/_posts/linux/xargs命令.md b/source/_posts/linux/xargs命令.md new file mode 100644 index 0000000..20ba8d6 --- /dev/null +++ b/source/_posts/linux/xargs命令.md @@ -0,0 +1,161 @@ +--- +title: xargs命令 +date: 2019-8-23 23:05:33 +tags: + - linux +categories: + - linux +--- + +`xargs`命令的作用可以概括为将标准输入转化为命令行参数 + + + +### 标准输入与管道符 + +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) + +要问带\n的字符串为啥这样写,我只能说shell的晦涩之处不止于此 +可以看到前一次执行了`ls -l -h` +后一次分别执行了`ls -l`和`ls -h` \ No newline at end of file