연구

연구

이것:

#!/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개의 54KB 라인이 있는 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 버전에서 작동하는지 확실하지 않습니다.

관련 정보