xargs 命令长度限制



我正在使用jsonlint来lint目录中的一堆文件(递归(。我写了以下命令:

find ./config/pages -name '*.json' -print0 | xargs -0I % sh -c 'echo Linting: %; jsonlint -V ./config/schema.json -q %;'

它适用于大多数文件,但有些文件出现以下错误:

Linting: ./LONG_FILE_NAME.json
fs.js:500
 return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
                ^
  Error: ENOENT, no such file or directory '%'

对于长文件名,它似乎失败。有没有办法解决这个问题?谢谢。

编辑 1:发现问题。

-I replstr

每个输入行的执行实用程序,替换一个或多个匹配项 最多替换的 replstr(如果未指定 -R 标志,则为 5( 整个输入行的实用程序参数。 结果 参数,替换完成后,将不允许增长 超过 255 字节;这是通过连接尽可能多的 参数尽可能包含 replstr,到结构化参数 到实用程序,最多 255 个字节。 255 字节限制不适用于 不包含 replstr 的效用论据,此外,没有 更换将在实用程序本身上进行。表示 -x。

编辑 2:部分解决方案。支持比以前更长的文件名,但仍然没有我需要的那么长。

find ./config/pages -name '*.json' -print0 | xargs -0I % sh -c 'file=%; echo Linting: $file; jsonlint -V ./config/schema.json -q $file;'

在类似 BSD 的系统(例如 Mac OS X(上

如果你碰巧在 mac 或 freebsd 等上,你的xargs实现可能支持选项 -J,它不受选项 -I 施加的参数大小限制的影响。

摘自手册页

-J replstr
If this option is specified, xargs will use the data read from standard input to replace the first occurrence of replstr instead of appending that data after all other arguments. This option will not effect how many arguments will be read from input (-n), or the size of the command(s) xargs will generate (-s). The option just moves where those arguments will be placed in the command(s) that are executed. The replstr must show up as a distinct argument to xargs. It will not be recognized if, for instance, it is in the middle of a quoted string. Furthermore, only the first occurrence of the replstr will be replaced. For example, the following command will copy the list of files and directories which start with an uppercase letter in the current directory to destdir:
/bin/ls -1d [A-Z]* | xargs -J % cp -Rp % destdir

如果需要多次引用repstr(*向上* TL;DR -J仅替换第一次出现(,则可以使用以下模式:

echo hi | xargs -J{} sh -c 'arg=$0; echo "$arg $arg"' "{}"
=> hi hi

符合 POSIX 标准的方法

执行此操作

的 posix 兼容方法是使用其他工具,例如 sed构造要执行的代码,然后使用 xargs 仅指定实用程序。当 xargs 中未使用 repl 字符串时,255 字节限制不适用。xargs POSIX 规格

find . -type f -name '*.json' -print |
  sed "s_^_-c 'file=\"_g;s_$_\"; echo \"Definitely over 255 byte script..$(printf "a%.0s" {1..255}): \$file\"; wc -l \"\$file\"'_g" |
  xargs -L1 sh

当然,这在很大程度上违背了一开始xargs的目的,但仍然可以用于利用例如使用xargs -L1 -P10 sh并行执行,这得到了相当广泛的支持,尽管不是posix。

在查找中使用-exec,而不是通过管道连接到 xarg。

find ./config/pages -name '*.json' -print0 -exec echo Linting: {} ; -exec jsonlint -V ./config/schema.json -q {} ;

xargs 的命令行长度限制是由系统(不是环境(变量ARG_MAX施加的。您可以像这样检查它:

$ getconf ARG_MAX
2097152

令人惊讶的是,除了内核修改之外,似乎没有办法改变它。

但更令人惊讶的是,默认情况下xargs被限制为一个低得多的值,你可以使用-s选项来增加。尽管如此,ARG_MAX不是您可以在-s之后设置的值 - 根据您需要减去环境大小man xargs加上一些"余量",不知道为什么。要找出实际数字,请使用以下命令(或者,对-s使用任意大数字将导致描述性错误(:

$ xargs --show-limits 2>&1 | grep "limit on argument length (this system)"
POSIX upper limit on argument length (this system): 2092120

所以你需要运行… | xargs -s 2092120 …,例如使用你的命令:

find ./config/pages -name '*.json' -print0 | xargs -s 2092120 -0I % sh -c 'echo Linting: %; jsonlint -V ./config/schema.json -q %;'

最新更新