linux args 长度,Linux xargs(每日一令之十七)

功能介绍:

xargs大多数 Linux 命令都会产生输出:文件列表、字符串列表等。但如果要使用其他某个命令并将前一个命令的输出作为参数该怎么办?例如,file 命令显示文件类型(可执行文件、ascii 文本等);你能处理输出,使其仅显示文件名,目前你希望将这些名称传递给 ls -l 命令以查看时间戳记。xargs 命令就是用来完成此项工作的。他允许你对输出执行其他某些命令。

xargs是给命令传递参数的一个过滤器,也是组合多个命令的一个工具。它把一个数据流分割为一些足够小的块,以方便过滤器和命令进行处理。通常情况下,xargs从管道或者stdin中读取数据,但是它也能够从文件的输出中读取数据。xargs的默认命令是echo,这意味着通过管道传递给xargs的输入将会包含换行和空白,不过通过xargs的处理,换行和空白将被空格取代。

如:

[root@uyhd000225 ~]# ll|xargs

总计 4834888 -rw-r--r-- 1 root root 0 07-08 13:39 =2013-06-22 -rw------- 1 root root 1137 2011-03-22 anaconda-ks.cfg drwxr-xr-x 7 root root 4096 12-06 23:44 Desktop -rw-r--r-- 1 root root 179539724 12-06 23:34 fund_netvalue_20131206.sql -rw-r--r-- 1 root root 274671799 11-08 13:58 fund_netvalue.sql -rw-r--r-- 1 root root 341811 12-07 00:05 fundnetvalue.sql -rw-r--r-- 1 root root 425 08-22 16:05 HelloWorld.class -rw-r--r-- 1 root root 104 08-22 16:04 HelloWorld.java -rw-r--r-- 1 root root 25051 07-08 14:25 history2.txt -rw-r--r-- 1 root root 24942 07-08 14:23 history.txt -rw-r--r-- 1 root root 50732 2011-03-22 install.log -rw-r--r-- 1 root root 4898 2011-03-22 install.log.syslog -rw-r--r-- 1 root root 7300 12-18 13:38 ls2.txt -rw-r--r-- 1 root root 7877 12-18 13:47 ls3.txt -rw-r--r-- 1 root root 9703 12-18 13:34 ls.txt -rw-r--r-- 1 root root 4491311119 11-26 14:35 mysqldb20131126.sql -rw-r--r-- 1 root root 39 12-10 13:32 n.sh -rw-r--r-- 1 root root 14 12-09 16:04 pwd.sh drwxr-xr-x 2 root root 4096 12-18 14:33 test -rw-r--r-- 1 root root 352 12-10 15:43 test2.sh

[root@uyhd000225 ~]# ll|xargs -0

总计 4834888

-rw-r--r-- 1 root root 0 07-08 13:39 =2013-06-22

-rw------- 1 root root 1137 2011-03-22 anaconda-ks.cfg

drwxr-xr-x 7 root root 4096 12-06 23:44 Desktop

--null, -0

Input items are terminated by a null character instead of by whitespace, and the quotes and backslash are not special (every character is taken literally).

Disables the end of file string, which is treated like any other argument. Useful when input items might contain white space, quote marks, or backslashes.

The GNU find -print0 option produces input suitable for this mode.

例子:

记住下面这个来自于第 1 部分中的语法:

[root@uyhd000225 ~]# file -Lz *

=2013-06-22: empty

anaconda-ks.cfg: ASCII English text

Desktop: directory

fund_netvalue_20131206.sql: ASCII text, with very long lines

fund_netvalue.sql: ASCII text, with very long lines

fundnetvalue.sql: UTF-8 Unicode text, with CRLF line terminators

HelloWorld.class: compiled Java class data, version 51.0

HelloWorld.java: ASCII C++ program text

history2.txt: ASCII C++ program text

history.txt: ISO-8859 C++ program text

install.log: ASCII text

install.log.syslog: ASCII text

ls2.txt: UTF-8 Unicode English text

ls3.txt: UTF-8 Unicode English text

ls.txt: UTF-8 Unicode English text, with overstriking

mysqldb20131126.sql: UTF-8 Unicode text, with very long lines

n.sh: ASCII text

pwd.sh: ASCII text

test: directory

test2.sh: Bourne shell script text executable

[root@uyhd000225 ~]# file -Lz * | grep ASCII

anaconda-ks.cfg: ASCII English text

fund_netvalue_20131206.sql: ASCII text, with very long lines

fund_netvalue.sql: ASCII text, with very long lines

HelloWorld.java: ASCII C++ program text

history2.txt: ASCII C++ program text

install.log: ASCII text

install.log.syslog: ASCII text

n.sh: ASCII text

pwd.sh: ASCII text

[root@uyhd000225 ~]# file -Lz * | grep ASCII | cut -d":" -f1 | xargs ls -ltr

-rw-r--r-- 1 root root 4898 2011-03-22 install.log.syslog

-rw-r--r-- 1 root root 50732 2011-03-22 install.log

-rw------- 1 root root 1137 2011-03-22 anaconda-ks.cfg

-rw-r--r-- 1 root root 25051 07-08 14:25 history2.txt

-rw-r--r-- 1 root root 104 08-22 16:04 HelloWorld.java

-rw-r--r-- 1 root root 274671799 11-08 13:58 fund_netvalue.sql

-rw-r--r-- 1 root root 179539724 12-06 23:34 fund_netvalue_20131206.sql

-rw-r--r-- 1 root root 14 12-09 16:04 pwd.sh

-rw-r--r-- 1 root root 39 12-10 13:32 n.sh

下面是另一个示例,我们希望计算这些文件中的行数:

[root@uyhd000225 ~]# file * | grep ASCII | cut -d":" -f1 | xargs wc -l

54 anaconda-ks.cfg

238 fund_netvalue_20131206.sql

329 fund_netvalue.sql

5 HelloWorld.java

1000 history2.txt

1215 install.log

56 install.log.syslog

4 n.sh

1 pwd.sh

2902 总计

同上功能:[root@uyhd000225 ~]# wc -l `file * | grep ASCII | cut -d":" -f1`

54 anaconda-ks.cfg

238 fund_netvalue_20131206.sql

329 fund_netvalue.sql

5 HelloWorld.java

1000 history2.txt

1215 install.log

56 install.log.syslog

4 n.sh

1 pwd.sh

2902 总计

[root@uyhd000225 ~]#

$ ls | xargs -t -i mv {} {}.bak-i 选项告诉 xargs 用每项的名称替换 {}。-t 选项指示 xargs 先打印命令,然后再执行。

[root@uyhd000225 test]# ll

总计 12

-rw-r--r-- 1 root root 7 12-11 14:01 1

-rw-r--r-- 1 root root 0 12-11 14:01 1fuwenchao

-rw-r--r-- 1 root root 0 12-11 10:54 2fuwenchao

-rw-r--r-- 1 root root 0 12-11 10:54 3fuwenchao

-rw-r--r-- 1 root root 0 12-11 10:54 4fuwenchao

-rw-r--r-- 1 root root 0 12-11 10:54 5

-rw-r--r-- 1 root root 10 12-11 13:01 son.sh

-rw-r--r-- 1 root root 7 12-11 14:01 wenchao

[root@uyhd000225 test]# ls | xargs -t -i mv {} {}.bak

mv 1 1.bak

mv 1fuwenchao 1fuwenchao.bak

mv 2fuwenchao 2fuwenchao.bak

mv 3fuwenchao 3fuwenchao.bak

mv 4fuwenchao 4fuwenchao.bak

mv 5 5.bak

mv son.sh son.sh.bak

mv wenchao wenchao.bak

$ file * | grep ASCII | cut -d":" -f1 | xargs vi该命令使用 vi 逐个打开文件。当你希望搜索多个文件并打开他们进行编辑时,使用该命令非常方便。他更有几个选项。最有用的可能是 -p 选项,他使操作具有可交互性:$ file * | grep ASCII | cut -d":" -f1 | xargs -p vivi alert_DBA102.log dba102_cjq0_14493.trc dba102_mmnl_14497.trcdba102_reco_14491.trc dba102_rvwr_14518.trc ?...此处的 xarg 需求你在运行每个命令之前进行确认。如果你按下 "y",则执行命令。当你对文件进行某些可能有破坏且不可恢复的操作(如删除或覆盖)时,你会发现该选项非常有用。-t 选项使用一个周详模式;他显示要运行的命令,是调试过程中一个非常有帮助的选项。如果传递给 xargs 的输出为空怎么办?考虑以下命令:[root@uyhd000225 ~]# file * | grep SSSSSS | cut -d":" -f1 | xargs -t wc -l

wc -l

0

在此处,搜索 "SSSSSS" 后没有匹配的内容;因此 xargs 的输入均为空,如第二行所示(由于我们使用 -t 这个周详选项而产生的结果)。虽然这可能会有所帮助,但在某些情况下,如果没有要处理的内容,你可能希望停止 xargs;如果是这样,能使用 -r 选项: $ file * | grep SSSSSS | cut -d":" -f1 | xargs -t -r wc -l

假设你希望使用 rm 命令(该命令将作为 xargs 命令的参数)删除文件。然而,rm 只能接受有限数量的参数。如果你的参数列表超出该限制怎么办?xargs 的 -n 选项限制单个命令行的参数个数。下面显示了怎么限制每个命令行仅使用两个参数:即使向 xargs ls -ltr 传递五个文件,但每次向 ls -ltr 仅传递两个文件。[root@uyhd000225 ~]# file * | grep ASCII | cut -d":" -f1 | xargs -t -n2 ls -ltr

ls -ltr anaconda-ks.cfg fund_netvalue_20131206.sql

-rw------- 1 root root 1137 2011-03-22 anaconda-ks.cfg

-rw-r--r-- 1 root root 179539724 12-06 23:34 fund_netvalue_20131206.sql

ls -ltr fund_netvalue.sql HelloWorld.java

-rw-r--r-- 1 root root 104 08-22 16:04 HelloWorld.java

-rw-r--r-- 1 root root 274671799 11-08 13:58 fund_netvalue.sql

ls -ltr history2.txt install.log

-rw-r--r-- 1 root root 50732 2011-03-22 install.log

-rw-r--r-- 1 root root 25051 07-08 14:25 history2.txt

ls -ltr install.log.syslog n.sh

-rw-r--r-- 1 root root 4898 2011-03-22 install.log.syslog

-rw-r--r-- 1 root root 39 12-10 13:32 n.sh

ls -ltr pwd.sh

-rw-r--r-- 1 root root 14 12-09 16:04 pwd.sh

[root@uyhd000225 ~]#

使用该方法,你能快速重命名目录中的文件。$ ls | xargs -t -i mv {} {}.bak-i 选项告诉 xargs 用每项的名称替换 {}。

[root@uyhd000225 ~]# find /etc -name "*.cnf" | xargs ls -l

-rw-r--r-- 1 root root 4992 09-30 10:26 /etc/my.cnf

-rw-r--r-- 1 root root 9828 2013-03-05 /etc/pki/tls/openssl.cnf

[root@uyhd000225 ~]# find /etc -name "*.cnf" | xargs ls -l {}

ls: {}: 没有那个文件或目录

-rw-r--r-- 1 root root 4992 09-30 10:26 /etc/my.cnf

-rw-r--r-- 1 root root 9828 2013-03-05 /etc/pki/tls/openssl.cnf

[root@uyhd000225 ~]# find /etc -name "*.cnf" | xargs -i ls -l {}

-rw-r--r-- 1 root root 4992 09-30 10:26 /etc/my.cnf

-rw-r--r-- 1 root root 9828 2013-03-05 /etc/pki/tls/openssl.cnf

[root@uyhd000225 ~]#

删除数量比较多的文件ls | xargs -n 20 rm -frls当然是输出所有的文件名(用空格分割)xargs就是将ls的输出,每20个为一组(以空格为分隔符),作为rm -rf的参数也就是说将所有文件名20个为一组,由rm -rf删除,这样就不会超过命令行的长度了

实例:

xargs 是一个强有力的命令,它能够捕获一个命令的输出,然后传递给另外一个命令,下面是一些如何有效使用xargs 的实用例子。

1. 当你尝试用rm 删除太多的文件,你可能得到一个错误信息:/bin/rm Argument list too long. 用xargs 去避免这个问题

find ~ -name ‘*.log’ -print0 | xargs -0 rm -f

2. 获得/etc/ 下所有*.conf 结尾的文件列表,有几种不同的方法能得到相同的结果,下面的例子仅仅是示范怎么实用xargs ,在这个例子中实用 xargs将find 命令的输出传递给ls -l

# find /etc -name "*.conf" | xargs ls –l

3. 假如你有一个文件包含了很多你希望下载的URL, 你能够使用xargs 下载所有链接

#cat url-list.txt | xargs wget –c

4. 查找所有的jpg 文件,并且压缩它

#find / -name *.jpg -type f -print | xargs tar -cvzf p_w_picpaths.tar.gz

5. 拷贝所有的图片文件到一个外部的硬盘驱动

# ls *.jpg | xargs -n1 -i cp {} /external-hard-drive/directory

EXAMPLESfind /tmp -name core -type f -print | xargs /bin/rm -fFind files named core in or below the directory /tmp and delete them.  Note that this will work incorrectly if there are any filenames containing newlines or spaces.find /tmp -name core -type f -print0 | xargs -0 /bin/rm -fFind  files  named core in or below the directory /tmp and delete them, processing filenames in such a way that file or directory names containing spaces or newlines are correctly handled.find /tmp -depth -name core -type f -deleteFind files named core in or below the directory /tmp and delete them, but more efficiently than in the previous example (because we avoid the need to use fork(2) and exec(2) to launch rm and we don't need the extra xargs process).cut -d: -f1 < /etc/passwd | sort | xargs echoGenerates a compact listing of all the users on the system.xargs sh -c 'emacs "$@" < /dev/tty' emacsLaunches the minimum number of copies of Emacs needed, one after the other, to edit the files listed on xargs' standard input.  This example achieves the same effect as BSD's -o option, but in a more flexible and portable way.

与find搭配时exec与xargs的区别:

xargs – build and execute command lines from standard input

在使用find命令的-exec选项处理匹配到的文件时, find命令将所有匹配到的文件一起传递给exec执行。但有些系统对能够传递给exec的命令长度有限制,这样在find命令运行几分钟之后,就会出现溢出错误。错误信息通常是“参数列太长”或“参数列溢出”。这就是xargs命令的用处所在,特别是与find命令一起使用。

find命令把匹配到的文件传递给xargs命令,而xargs命令每次只获取一部分文件而不是全部,不像-exec选项那样。这样它可以先处理最先获取的一部分文件,然后是下一批,并如此继续下去。

在有些系统中,使用-exec选项会为处理每一个匹配到的文件而发起一个相应的进程,并非将匹配到的文件全部作为参数一次执行;这样在有些情况下就会出现进程过多,系统性能下降的问题,因而效率不高;

而使用xargs命令则只有一个进程。另外,在使用xargs命令时,究竟是一次获取所有的参数,还是分批取得参数,以及每一次获取参数的数目都会根据该命令的选项及系统内核中相应的可调参数来确定。

来看看xargs命令是如何同find命令一起使用的,并给出一些例子。

下面的例子查找系统中的每一个普通文件,然后使用xargs命令来测试它们分别属于哪类文件#find . -type f -print | xargs file

./.kde/Autostart/Autorun.desktop: UTF-8 Unicode English text

./.kde/Autostart/.directory: ISO-8859 text\

......

在整个系统中查找内存信息转储文件(core dump) ,然后把结果保存到/tmp/core.log 文件中:$ find / -name "core" -print | xargs echo "" >/tmp/core.log

上面这个执行太慢,我改成在当前目录下查找#find . -name "file*" -print | xargs echo "" > /temp/core.log

# cat /temp/core.log

./file6

xargs 命令读取标准的输入,然后使用参数作为输入构建和执行命令。如果没有给出命令,那么将使用 echo 命令。清单 12 是使用我们的 text1 文件的基础例子,它包含 3 个行,每行只有两个单词。[ian@echidna lpi103-4]$ cat text11 apple2 pear3 banana[ian@echidna lpi103-4]$ xargs

为什么 xargs 只有一行输出?默认情况下,xargs 在空格处中断输出,并且每个生成的标记都成为一个参数。不过,当 xargs 构建命令时,它将一次传递尽可能多的参数。您可以使用 -n 覆盖该行为,或使用 --max-args 参数。在清单 13 中,我们使用了这两种方法,并为使用xargs 添加一个显式的 echo 调用。[ian@echidna lpi103-4]$ xargs"args > 1 apple 2 pear 3 banana[ian@echidna lpi103-4]$ xargs --max-args 3 "args > 1 apple 2args > pear 3 banana[ian@echidna lpi103-4]$ xargs -n 1 "args > 1args > appleargs > 2args > pearargs > 3args > banana

如果输入包含由单引号或双引号保护的空格,或使用了斜杠进行转义,那么 xargs 将不在遇到这些空格时中断。清单 14 显示了这些空格点。[ian@echidna lpi103-4]$ echo '"4 plum"' | cat text1 -1 apple2 pear3 banana"4 plum"[ian@echidna lpi103-4]$ echo '"4 plum"' | cat text1 - | xargs -n 11apple2pear3banana4 plum

到目前为止,已经在命令的末尾添加了所有参数。如果您需要在这些参数后面再使用其他参数,可以使用 -I 选项指定一个替换字符串。如果 xargs 将要执行的命令包含有替换字符串,那么将使用参数替换它。进行了替换之后,仅将参数传递给每个命令。不过,将从一整行输出创建参数,而不仅是一个标记。您 还可以使用 xargs 的 -L 选项让命令将行当作参数看待,而不是默认的以单个空格分隔的标记。使用 -I 选项表示 -L 1。 清单 15 显示了使用 -I 和 -L 选项的例子。[ian@echidna lpi103-4]$ xargs -I XYZ echo "START XYZ REPEAT XYZ END" " <9 plum><3 banana><3 banana><10 apple><10 apple>[ian@echidna lpi103-4]$ cat text1 text2 | xargs -L21 apple 2 pear3 banana 9 plum3 banana 10 apple

尽管我们的例子为了便于演示使用了简单的文本文件,您很少看到包含这样的输入的 xargs。您通常需要处理某些 命令生成的大量文件,这些命令包括 ls、find 或 grep。清 单 16 显示了一种通过 xargs 将目录清单传递到命令(比如 grep)的方法。[ian@echidna lpi103-4]$ ls |xargs grep "1"text1:1 appletext2:10 applexaa:1 appleyaa:1

如果上一个例子中的一个或多个文件名包含空格,那么会发生什么呢?如果您像清单 16 那样使用该命令,那么将得到一个错误。在实际情况中,文件列表可能来自一些源,比如定制脚本或命令,而不是 ls,或者您希望 通过其他管道线阶段传递它,以进一步进行过滤。所以您应该使用 grep "1" * 取代以上构造。

对于 ls 命令,您可以使用 --quoting-style 选项强制给导致问题的文件名加上引号或进行转义。另外一种更好的解决办法是使用 xargs 的 -0 选项,从而使用 null 字符串 (\0) 分隔输入参数。尽管 ls 没有提供使用 null 字符串分隔的文件名作为输出的选项,但许多命令都提供这样的选项。

在清单 17 中,我们首先将 text1 复制到 “text 1”,然后显示一些在 xargs 命令中使用包含空格的文件名列表的方法。这些示例仅为了演示概念,因为 xargs 可能更加复杂。尤其是在最后一个例子中, 如果一些文件名已经包含新行字符串,那么将新行字符串转换成 null 字符串将导致错误。在本文的下一个部分中,我们将查看另外一个更加健壮的解决方案,即使用 find 命令生成合适的以 null 字符串分隔的输出。[ian@echidna lpi103-4]$ cp text1 "text 1"[ian@echidna lpi103-4]$ ls *1 |xargs grep "1" # errortext1:1 applegrep: text: No such file or directorygrep: 1: No such file or directory[ian@echidna lpi103-4]$ ls --quoting-style escape *1text1 text\ 1[ian@echidna lpi103-4]$ ls --quoting-style shell *1text1 'text 1'[ian@echidna lpi103-4]$ ls --quoting-style shell *1 |xargs grep "1"text1:1 appletext 1:1 apple[ian@echidna lpi103-4]$ # Illustrate -0 option of xargs[ian@echidna lpi103-4]$ ls *1 | tr '\n' '\0' |xargs -0 grep "1"text1:1 appletext 1:1 apple

xargs 命令不会构建任意长度的命令。在 Linux 内核 2.26.3 之前,命令的长度是受限制的。针对某个包含大量名称很长的文件的目录的命令,比如 rm somepath/*,可能会失败, 返回的消息表明参数列表太长。在更旧的 Linux 系统或 UNIX 系统上仍然存在该限制,因此了解如何使用 xargs 以处理这种问题非常有用。

您可以使用 --show-limits 选项显示 xargs 的默认限制,然后使用 -s 选项将输出命令的长度限制在允许的最大字符串数量之内。查看手册页了解其他未能再次讨论的选项。

在文章 “学习 Linux,101:文件和目录管理” 中,您学习例如如何使用 find 命令根据名称、修改时间、大小或其他特征查找文件。找到匹配的文件集之后,您通常希望对它们执行某些操作:删除、移动和重命名它们等。现在我们看一下 find 命令的 -exec 选项,其功能类似于使用 find 并通过管道将输出指向 xargs。[ian@echidna lpi103-4]$ find text[12] -exec cat text3 {} \;This is a sentence. This is a sentence. This is a sentence.1 apple2 pear3 bananaThis is a sentence. This is a sentence. This is a sentence.9 plum3 banana10 apple

与前面学习的 xargs 命令相比,它有几个不同之处。您必须使用 {} 标记文件名在命令中的位置。它不是自动添加在末尾的。

您必须使用转义后的分号终止该命令,比如 \;、';' 或 ";" 都行。

该命令对每个输入文件执行一次。

尝试运行 find text[12] |xargs cat text3 亲自看看区别在哪里。

现在,我将话题转回到文件名中的空格。在清单 19 中我们尝试使用带有 -exec 的 find, 而不是带有 xargs 的 ls。[ian@echidna lpi103-4]$ find . -name "*1" -exec grep "1" {} \;1 apple1 apple

到目前为止,一切进展顺利。但是不是缺少了什么?哪个文件包含 grep 找到行?缺少了文件名,因为 find 为每个文件调用 grep 一次,而grep 非常智能,能够知道您是不是仅提供文件名,您不需要它告诉您是哪个文件。

我们也可以改为使用 xargs,但我们已经看到了文件名中包含空格时出现的问题。我们还提到 find 可以生成一个以 null 分隔符分隔的文件名列表,这是 -print0 选项所起的作用。新的 find 可能使用加号(+)取代分号(;)作为分隔符,这允许 find 在一次调用命令时传递尽可能多的名称,类似于 xargs。 在这种情况中,仅能使用 {} 一次,并且它必须是该命令的最后一个参数。清单 20 显示了这两种方法。[ian@echidna lpi103-4]$ find . -name "*1" -print0 |xargs -0 grep "1"./text 1:1 apple./text1:1 apple[ian@echidna lpi103-4]$ find . -name "*1" -exec grep "1" {} +./text 1:1 apple./text1:1 apple

一般而言,两种方法都是有效的,选择哪种方法由您决定。记住,使用管道导出包含未受保护的空格的内容将导致问题,因此如果您要使用管道将输出 导出到 xargs,请使用将 -print0 选项和 find 结合使用,并使用 -0 选项告诉 xargs 接收使用 null 分隔符分隔的输入。其他命令,包括 tar,也支持使用 -0 选项并用 null 分隔符分隔的输入,因此应该对支持该选项的命令使用它,除非您能确保您的输入列表不会造成问题。

最后,我们介绍对文件列表进行操作。在执行删除或重命名文件等重要操作之前,最好彻底地测试列表和仔细测试命令。进行良好的备份也是非常有价 值的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值