研究

研究

これ:

#!/bin/bash

# Run command ~100Kbytes long
/bin/echo $(perl -e 'print "x"x100000') | wc
# Run command ~54Kbytes long
# This line fails: line 7: /bin/echo: Argument list too long
/bin/echo $(perl -e 'print "x "x27000') | wc

# Same command, but run using xargs
# Run command ~100Kbytes long
perl -e 'print "x"x100000' | xargs -n 100000 /bin/echo | wc
# Run command ~54Kbytes long
# This line fails: xargs: /bin/echo: Argument list too long
perl -e 'print "x "x27000' | xargs -n 100000 /bin/echo | wc

GNU/Linux ではうまく動作しますが、2 つの 54 KB ラインがある MacOS X では失敗します。

ARG_MAX100KBytesよりはるかに高いので、100Kbytesラインは次のようになります。いいえ失敗 - 54KBytes 行が失敗しました。

mac$ getconf ARG_MAX
262144
mac$ uname -a
Darwin macosx 11.4.2 Darwin Kernel Version 11.4.2: Thu Aug 23 16:26:45 PDT 2012; root:xnu-1699.32.7~1/RELEASE_I386 i386
# Kusalananda suggests it may be due to the size of the environment
mac$ env | wc
      27      32     956

54Kbytesコマンドが失敗するのはなぜですか?

MacOS Xで引数リストを実行せずに引数リストが長すぎるかどうかを予測する方法はありますか?

研究

これ:

#!/bin/bash

runtest() {
    echo environment size:
    env | wc
    echo Run command ~100Kbytes long
    /bin/echo $(perl -e 'print "x"x100000') | wc
    echo Run command ~54Kbytes long
    # This line fails: line 7: /bin/echo: Argument list too long
    /bin/echo $(perl -e 'print "x "x27000') | wc
    
    # Same command, but run using xargs
    echo Run command ~100Kbytes long
    perl -e 'print "x"x100000' | xargs -n 100000 /bin/echo | wc
    echo Run command ~54Kbytes long
    # This line fails: xargs: /bin/echo: Argument list too long
    perl -e 'print "x "x27000' | xargs -n 100000 /bin/echo | wc
    echo
}

# Clean environment
runtest

# Make a huge environment
for a in `seq 5000`; do eval "a$a=1" ; done
for a in `seq 5000`; do eval "a$a() { 1; }" ; done
# This works as before
runtest

# Export environment
for a in `seq 5000`; do eval export a$a ; done
for a in `seq 5000`; do eval export -f a$a ; done
# Now the 100Kbytes commands fail, too
runtest

次の出力を提供します。

environment size:
    6027    6032   47849
Run command ~100Kbytes long
       1       1  100001
Run command ~54Kbytes long
test: line 10: /bin/echo: Argument list too long
       0       0       0
Run command ~100Kbytes long
       1       1  100001
Run command ~54Kbytes long
xargs: /bin/echo: Argument list too long
       0       0       0

environment size:
    6027    6032   47849
Run command ~100Kbytes long
       1       1  100001
Run command ~54Kbytes long
test: line 10: /bin/echo: Argument list too long
       0       0       0
Run command ~100Kbytes long
       1       1  100001
Run command ~54Kbytes long
xargs: /bin/echo: Argument list too long
       0       0       0

environment size:
   16027   26032  126742
Run command ~100Kbytes long
test: line 7: /bin/echo: Argument list too long
       0       0       0
Run command ~54Kbytes long
test: line 10: /bin/echo: Argument list too long
       0       0       0
Run command ~100Kbytes long
xargs: insufficient space for argument
       0       0       0
Run command ~54Kbytes long
xargs: /bin/echo: Argument list too long
       0       0       0

だからクサロナンダは正しかった。出口環境が影響を与える可能性があります。これを計算する式が何であるかは不明です。純粋に大きさかもしれません。たぶん変数の数が重要ですか?おそらく名前の長さのためですか?おそらくこれらの線形の組み合わせですか?

それまだ特定の環境では、100Kbytesコマンドが正しく機能するという説明はありませんが、54Kbytesコマンドはそうではありません。

MacOSにはフルサイズだけでなく、パラメータの数にも制限があるようです。

これは、MacOSがパラメータごとにさらに8バイトを使用している場合でも意味があります。

# One big argument
100K * "x" = 100000+2 < 262144 # Works
# 27K small arguments
27K * "x " = 27K*(8+2) > 262144 # Fails
# 26K small arguments
26K * "x " = 26K*(8+2) < 262144 # Works

しかし、MacOSはこれを行うことができますか?

答え1

追加の調査結果が公開されました(MacOSバージョンは不明)。

Effective length = 
  length of arguments +
  5 * number of arguments +
  length of body/value of exported functions/variables +
  length of names of exported functions/variables +
  4 * number of exported functions/variables

有効長が256KB未満の場合、コマンドが実行されます。これがすべてのMacOSバージョンで動作するかどうかはわかりません。

MacOS El Capitan 10.11.4の場合、これは悲観的なコマンドラインの長さを提供します(実行したいコマンドは次のように見なされます/bin/echo x x x x ...)。

perl -e '                                                                             
  $envc=(keys %ENV);                                                                    
  $envn=length join"",(keys %ENV);                                                      
  $envv=length join"",(values %ENV);                                                    
  $maxlen=3+(262144 - $envn - $envv) / 5 - $envc*2;                                     
  print("Max len = $maxlen\n");
'                                                        

これがすべてのMacOSバージョンで動作するかどうかはわかりません。

関連情報