bash 스크립트 실행 시 $0 및 모든 매개변수가 사라지는 이유는 무엇입니까(ps에 표시됨)?

bash 스크립트 실행 시 $0 및 모든 매개변수가 사라지는 이유는 무엇입니까(ps에 표시됨)?

bash 스크립트(첫 번째 줄 #! /bin/bash) 가 있고 do-dorunsbash 명령줄에서 호출합니다../do-doruns arg1 arg2 ...

이 스크립트는 차례로 scripts 를 호출 ./dorun a1 a2 a3 ...하며 더 많은 수준의 스크립트가 있으며 컴파일된 프로그램을 호출합니다.

ps및 를 사용하여 보면 dorun그 아래에서 호출되는 모든 실행 중인 항목에는 ps해당 이름과 명령줄 인수가 표시됩니다. 예를 들어 다음과 같습니다.

/bin/bash /home/moss/path-to-dorun/dorun a1 a2 a3

등. 그러나 어떤 do-doruns선도 표시되지 않습니다. 확실히 실행 중입니다(하위 프로세스가 완료되기를 기다리고 있음). 왜 그랬는지 이해할 수 있어논쟁사라질 수 있지만(별도의 테스트에서 shiftbash를 사용하면 인수가 사라지지 않는 것으로 나타났지만 ps) 해당 $0명령 이름은 사라지지 않습니다.

이것이 내 작업에 방해가 되는 것은 아니지만, 꼭 알고 싶은 이상한 미스터리입니다. 사물의 버전은 다음과 같습니다.

  • uname -a보여주다:Linux moss-Ubuntu-SMCSim 5.4.0-81-generic #91-Ubuntu SMP Thu Jul 15 19:09:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

  • bash --version보여주다:GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)

  • ps --version표시되는 내용(아마도 이상하게도):ps from procps-ng UNKNOWN

    이 동작은 이에 국한되지 않고 pstop기본적으로 보이도록 표시됩니다.

  • 마지막으로, 이것이 중요하다면 이 모든 것이 VirtualBox 가상 머신에서 실행되고 있다는 것입니다.

    vboxmanage --version보여주다:7.0.4r154605

답변1

ps -C이는 options 에서 사용하는 명령 이름을 변경 하고 grep과 일치하는 방법(사용하는 플래그에 따라 다름)을 변경하므로 스크립트의 첫 번째 줄이 어떻게 보이는지에 따라 달라질 수 있습니다 .

다음과 같은 것을 사용하십시오

#!/bin/bash

명령 이름을 스크립트 이름으로 변경하므로 do-dorun으로 표시됩니다.

사용

#!/bin/env bash

이는 명령 이름이 bash로 유지됨을 의미합니다.

두 가지 모두에 대한 명령줄은 동일하게 보입니다. 예를 들어/bin/bash myscriptname.sh arg1 arg2 arg3

답변2

eval추가 연구, 즉 스크립트를 최소한의 테스트 사례로 축소한 결과 이 ​​동작은 bash의 내장 기능을 사용했기 때문에 발생한 것으로 나타났습니다 . 최소 테스트 케이스는 다음과 같습니다.

#! /bin/bash
eval foo xyz

foo실행할 다른 스크립트는 어디에 있습니까? (특별히 테스트하지는 않았지만 프로그램에서도 이런 일이 발생할 수 있습니다.)

무슨 일이 일어나고 있는 것 같으면 eval쉘이 명령줄 옵션 fork-exec a를 bash사용하여 명령줄을 실행하게 만드는 것입니다. -c그러한 bash 호출로 인해 명령줄에 빈 작업이 표시되는 것 같습니다. 명령줄을 읽은 다음 bash는 필요한 프로그램만 실행하기 때문인 것 같습니다.

그래서 이런 동작을 원하지 않는다면 eval.

알아낼 수 있도록 도와주셔서 감사합니다!

답변3

exec후속 명령이 exec호출 쉘을 대체하므로 쉘의 명령줄을 변경하는 쉬운 방법이 있습니다 . /proc/pid/cmdline여기서 인쇄물을 아름답게 한다는 의견을 고려하면 버전 2입니다. 그러나 eval을 사용하여 변수에 준비된 명령을 실행하는 방법이 exec.

예시 v2:

#!/bin/bash

identifyMyself() {
echo "My cmdline: $0 My arg1: $1 My PID: $BASHPID"
echo "Kernel says:"
#cat -A /proc/$BASHPID/cmdline
#echo
readarray -d '' -t cmdline < /proc/$$/cmdline
#declare -p cmdline
printf '%s ' "${cmdline[@]}"
echo
}

identifyMyself "$1"

if [ -z "$1" ]
then
echo "calling myself with long parameters"
"$0" arg1 arg2 arg3 arg4
fi

if [ -z "$1" ]
then
dorun="$0 arg1 arg2 arg3 arg4"
echo "calling myself with long parameters by evaling a variable"
eval "${dorun}"
fi

if [ -z "$1" ]
then
echo "I am still here"
identifyMyself "$1"
fi

if [ -z "$1" ]
then
echo "execing myself with long parameters"
exec "$0" arg1 arg2 arg3 arg4
fi

if [ -z "$1" ]
then
echo "now I am gone"
identifyMyself "$1"
fi

산출:

$ ./bashtestv2_pid.sh
My cmdline: ./bashtestv2_pid.sh My arg1:  My PID: 1444428
Kernel says:
/bin/bash ./bashtestv2_pid.sh 
calling myself with long parameters
My cmdline: ./bashtestv2_pid.sh My arg1: arg1 My PID: 1444429
Kernel says:
/bin/bash ./bashtestv2_pid.sh arg1 arg2 arg3 arg4 
calling myself with long parameters by evaling a variable
My cmdline: ./bashtestv2_pid.sh My arg1: arg1 My PID: 1444430
Kernel says:
/bin/bash ./bashtestv2_pid.sh arg1 arg2 arg3 arg4 
I am still here
My cmdline: ./bashtestv2_pid.sh My arg1:  My PID: 1444428
Kernel says:
/bin/bash ./bashtestv2_pid.sh 
execing myself with long parameters
My cmdline: /home/user/bin/bashtestv2_pid.sh My arg1: arg1 My PID: 1444428
Kernel says:
/bin/bash /home/user/bin/bashtestv2_pid.sh arg1 arg2 arg3 arg4 

명령줄이 변경되면 실행 후 PID가 어떻게 동일하게 유지되는지 확인하세요. eval일반 통화처럼 작동합니다 . 귀하께서 댓글에서 말씀하신 내용은 다음과 같습니다. 그러나 당신 자신의 대답에서는 정반대라고 말합니다. 암시 evalexec.

관련 정보