xargs命令长度限制

问题描述 投票:4回答:3

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

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;'

bash xargs jsonlint
3个回答
2
投票

On BSD like systems (e.g. Mac OS X)

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

Excert from manpage

-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 compliant method

符合posix标准的方法是使用一些其他工具,例如sed构造您想要执行的代码,然后使用xargs来指定实用程序。如果在xargs中没有使用repl字符串,则不适用255字节限制。 xargs POSIX spec

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。


0
投票

在find中使用-exec而不是管道到xargs。

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


0
投票

xargs命令行长度的限制是由系统(非环境)变量ARG_MAX强加的。你可以检查它:

$ getconf ARG_MAX
2097152

令人惊讶的是,有doesn't not seem to be a way to change it, barring kernel modification

但更令人惊讶的是,xargs默认情况下上限值更低,你可以用-s选项增加。仍然,ARG_MAX不是你在-s - acc之后设置的值。到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 %;'
© www.soinside.com 2019 - 2024. All rights reserved.