简体   繁体   English

xargs命令长度限制

[英]xargs command length limits

I am using jsonlint to lint a bunch of files in a directory (recursively). 我正在使用jsonlint在目录中递归一堆文件(递归)。 I wrote the following command: 我写了以下命令:

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

It works for most files but some files I get the following error: 它适用于大多数文件,但有些文件我收到以下错误:

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

It appears to fail for long filenames. 它似乎因长文件名而失败。 Is there a way to fix this? 有没有办法来解决这个问题? Thanks. 谢谢。

Edit 1: Found the problem. 编辑1:发现问题。

-I replstr

Execute utility for each input line, replacing one or more occurrences of replstr in up to replacements (or 5 if no -R flag is specified) arguments to utility with the entire line of input. 为每个输入行执行实用程序,将整个替换项中的一个或多个replstr替换为(或者如果未指定-R标志,则为5)将整个输入行替换为实用程序。 The resulting arguments, after replacement is done, will not be allowed to grow beyond 255 bytes; 替换完成后,结果参数将不允许超过255个字节; this is implemented by concatenating as much of the argument containing replstr as possible, to the con-structed arguments to utility, up to 255 bytes. 这是通过将尽可能多的包含replstr的参数连接到实用程序的构造参数来实现的,最多255个字节。 The 255 byte limit does not apply to arguments to utility which do not contain replstr, and furthermore, no replacement will be done on utility itself. 255字节限制不适用于不包含replstr的实用程序的参数,此外,不会对实用程序本身进行替换。 Implies -x. 意味着-x。

Edit 2: Partial solution. 编辑2:部分解决方案。 Supports longer file names than before but still not as long as I need. 支持比以前更长的文件名,但仍然没有我需要的时间。

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

On BSD like systems (eg Mac OS X) 在类似BSD的系统上(例如Mac OS X)

If you happen to be on a mac or freebsd etc. your xargs implementation may support option -J which does not suffer from the argument size limits imposed on option -I . 如果你碰巧在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

If you need to refer to the repstr multiple times (*points up* TL;DR -J only replaces first occurrence) you can use this pattern: 如果需要多次引用repstr (*向上* TL; DR -J仅替换第一次出现),您可以使用此模式:

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

POSIX compliant method 符合POSIX的方法

The posix compliant method of doing this would be to use some other tool, eg sed to construct the code you want to execute and then use xargs to just specify the utility. 执行此操作的posix兼容方法是使用其他一些工具,例如sed来构造您想要执行的代码,然后使用xargs来指定实用程序。 When no repl string is used in xargs the 255 byte limit does not apply. 如果在xargs中没有使用repl字符串,则不适用255字节限制。 xargs POSIX spec 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

This of course largely defeats the purpose of xargs to begin with, but can still be used to leverage eg parallel execution using xargs -L1 -P10 sh which is quite widely supported, though not posix. 这当然在很大程度上打破了xargs开始的目的,但仍然可以用来利用例如使用xargs -L1 -P10 sh并行执行,这是非常广泛支持的,尽管不是posix。

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

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

The limit on xargs 's command line length is imposed by the system (not an environment) variable ARG_MAX . xargs命令行长度的限制是由系统(非环境)变量ARG_MAX You can check it like: 你可以检查它:

$ getconf ARG_MAX
2097152

Surprisingly, there doesn't not seem to be a way to change it, barring kernel modification . 令人惊讶的是, 除非内核修改,否则似乎没有办法改变它

But even more surprising that xargs by default gets capped to a much lower value, and you can increase with -s option. 但更令人惊讶的是,默认情况下, xargs的上限值要低得多,您可以使用-s选项进行增加。 Still, ARG_MAX is not the value you can set after -s — acc. 但是,ARG_MAX不是您在-s - acc之后可以设置的值。 to man xargs you need to subtract size of environment, plus some "headroom", no idea why. 对于man xargs你需要减去环境的大小,加上一些“净空”,不知道为什么。 To find out the actual number use the following command (alternatively, using an arbitrary big number for -s will result in a descriptive error) : 要查找实际数字,请使用以下命令(或者,对-s使用任意大数字将导致描述性错误)

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

So you need to run … | xargs -s 2092120 … 所以你需要运行… | xargs -s 2092120 … … | xargs -s 2092120 … , eg with your command: … | xargs -s 2092120 … ,例如使用您的命令:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM