【问题标题】:xargs command length limitsxargs 命令长度限制
【发布时间】:2016-07-13 11:52:51
【问题描述】:

我正在使用 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;'

【问题讨论】:

  • 看起来问题出在 jsonlint,而不是 xargs
  • 这是 xargs,我发现问题只是不是一个很好的解决方案。查看修改。
  • 您可以通过传递-n 1 告诉xargs 一次处理一个json 文件。或者,例如通过 -n 20 一次传递的文件数量可能少于断点。
  • 我认为这不会有帮助。将-I 标志与xargs 一起使用时,命令的限制为255 个字符。所以如果命令长度为 78 个字符,则文件名只能是 177 个字符。
  • 如果你删除了回声,你就可以放弃-Ifind ...|xargs jsonlint -V ./config.schema.json -q 另一种选择是在 for 循环中执行此操作。 for file in `find ...`; do echo "Linting: $file"; jsonlint -V .... $file; done;

标签: bash xargs jsonlint


【解决方案1】:

在类似 BSD 的系统上(例如 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 兼容方法

执行此操作的 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,但得到了广泛支持。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      在 find 中使用 -exec 而不是通过管道连接到 xargs。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-02-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-26
        • 1970-01-01
        • 2013-10-25
        • 2010-12-06
        相关资源
        最近更新 更多