$BASH_COMMAND 변수는 어디에 좋은가요?

$BASH_COMMAND 변수는 어디에 좋은가요?

에 따르면배쉬 매뉴얼, 환경 변수에는 다음이 BASH_COMMAND포함됩니다.

현재 실행 중이거나 곧 실행될 명령입니다. 단, 쉘이 트랩의 결과로 명령을 실행하는 경우는 트랩 시 실행되는 명령입니다.

함정에 빠진 경우를 제쳐두고, 내가 올바르게 이해했다면 이는 명령을 실행할 때 변수에 BASH_COMMAND해당 명령이 포함된다는 의미입니다. 명령 실행 후 해당 변수가 설정 해제되었는지 여부는 확실하지 않습니다.~하는 동안명령이 실행 중이지만 이후에는 실행되지 않음), "명령"이기 때문에 주장할 수도 있습니다.현재처형당하거나곧 될 것이다실행됨", 명령이 아닙니다.그건 그냥 그랬어실행.

하지만 확인해 봅시다:

$ set | grep BASH_COMMAND=
$ 

비어 있는. 나는 볼 것이라고 예상했거나 BASH_COMMAND='set | grep BASH_COMMAND='어쩌면 단지 BASH_COMMAND='set', 그러나 비어 있음이 나를 놀라게했습니다.

다른 것을 시도해 봅시다:

$ echo $BASH_COMMAND
echo $BASH_COMMAND
$ 

글쎄요. 명령을 실행 echo $BASH_COMMAND하면 변수에 BASH_COMMAND문자열이 포함됩니다 echo $BASH_COMMAND. 이번에는 작동했지만 이전에는 작동하지 않았던 이유는 무엇입니까?

set다시 해보자 :

$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$

그러니 기다리세요. 그것~였다echo해당 명령을 실행할 때 설정되었으며아니였다나중에 설정 해제됩니다. 그런데 다시 처형을 해보니 set,BASH_COMMAND 아니였다명령 으로 설정합니다 set. 여기서 명령 을 얼마나 자주 실행하더라도 set결과는 동일하게 유지됩니다. 그러면 을 실행할 때는 변수가 설정되지만 를 echo실행할 때는 설정되지 않습니까 set? 어디 보자.

$ echo Hello AskUbuntu
Hello AskUbuntu
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$

무엇?echo $BASH_COMMAND그래서 실행할 때 변수가 설정되었지만~ 아니다내가 처형했을 때 echo Hello AskUbuntu? 이제 차이점은 무엇입니까? 현재 명령 자체가 실제로 쉘이 변수를 평가하도록 강제하는 경우에만 변수가 설정됩니까? 다른 것을 시도해 봅시다. 이번에는 bash 내장이 아닌 일부 외부 명령을 변경해야 할 수도 있습니다.

$ /bin/echo $BASH_COMMAND
/bin/echo $BASH_COMMAND
$ set | grep BASH_COMMAND=
BASH_COMMAND='/bin/echo $BASH_COMMAND'
$

흠, 알겠습니다... 이번에도 변수가 설정되었습니다. 그럼 내 현재 추측이 맞는 걸까? 변수는 평가해야 할 때만 설정됩니까? 왜?왜?성능상의 이유로? 한 번 더 시도해 보겠습니다. $BASH_COMMAND파일에서 grep을 시도할 것이며 명령이 $BASH_COMMAND포함되어야 하므로 해당 명령(즉, 자체에 대해)을 grep해야 합니다. 적절한 파일을 만들어 보겠습니다.grepgrepgrep

$ echo -e "1 foo\n2 grep\n3 bar\n4 grep \$BASH_COMMAND tmp" > tmp
$ grep $BASH_COMMAND tmp
grep: $BASH_COMMAND: No such file or directory
tmp:2 grep                                      <-- here, the word "grep" is RED
tmp:4 grep $BASH_COMMAND tmp                    <-- here, the word "grep" is RED
tmp:2 grep                                      <-- here, the word "grep" is RED
tmp:4 grep $BASH_COMMAND tmp                    <-- here, the word "grep" is RED
$ set | grep BASH_COMMAND=
BASH_COMMAND='grep --color=auto $BASH_COMMAND tmp'
$

좋아, 흥미롭다. 명령이 grep $BASH_COMMAND tmp확장되었습니다 grep grep $BASH_COMMAND tmp tmp(물론 변수는 한 번만 확장됩니다). 그래서 존재하지 않는 grep파일에서 한 번 , 파일에서 두 번 grep을 했습니다 .$BASH_COMMANDtmp

Q1:내 현재 가정은 다음과 같습니다.

  • BASH_COMMAND명령이 실제로 이를 평가하려고 시도할 때만 설정됩니다. 그리고
  • 그것은~ 아니다설명을 보면 그렇게 믿게 되더라도 명령 실행 후 설정이 해제됩니까?

Q2:그렇다면 왜 그렇습니까? 성능? 그렇지 않다면 위 명령 시퀀스의 동작을 어떻게 설명할 수 있습니까?

Q3:마지막으로, 이 변수가 실제로 의미있게 사용될 수 있는 시나리오가 있습니까? 실제로는 실행 중인 명령을 분석하기 위해(그리고 이에 따라 몇 가지 작업을 수행하기 위해) 내에서 이를 사용하려고 했지만 할 수 없습니다. 왜냐하면 내 내에서 변수를 보기 위해 명령을 실행 $PROMPT_COMMAND하자마자 , 변수 해당 명령으로 설정됩니다. my 의 시작 부분에서 바로 수행하더라도 할당 도 명령이기 때문에 문자열이 포함됩니다 . (이 질문은 실행 중에 현재 명령을 어떻게 얻을 수 있는지에 관한 것이 아닙니다 . 다른 방법도 있다는 것을 알고 있습니다.)$PROMPT_COMMAND$BASH_COMMANDMYVARIABLE=$BASH_COMMAND$PROMPT_COMMANDMYVARIABLEMYVARIABLE=$BASH_COMMAND$PROMPT_COMMAND

하이젠베르크의 불확정성 원리와 약간 비슷합니다. 변수를 관찰하는 것만으로도 변경됩니다.

답변1

세 번째 질문에 대한 답: 물론 Bash 매뉴얼에서 명확하게 힌트를 제공하는 방식으로 의미 있게 사용될 수 있습니다. 예를 들어 트랩에서:

$ trap 'echo ‘$BASH_COMMAND’ failed with error code $?' ERR
$ fgfdjsa
fgfdjsa: command not found
‘fgfdjsa’ failed with error code 127
$ cat /etc/fgfdjsa
cat: /etc/fgfdjsa: No such file or directory
‘cat /etc/fgfdjsa’ failed with error code 1

답변2

이제 Q3에 대한 답이 나왔으니(내 생각에는 BASH_COMMAND트랩에만 유용하고 다른 곳에서는 거의 유용하지 않음) Q1과 Q2에 대해 한번 시도해 보겠습니다.

Q1에 대한 대답은 다음과 같습니다. 가정의 정확성은 결정할 수 없습니다. 불특정 행동에 대해 질문하기 때문에 두 항목 모두 진실을 밝힐 수 없습니다. 사양에 따라 값은 BASH_COMMAND해당 명령이 실행되는 동안 명령 텍스트로 설정됩니다. 사양에는 다른 상황, 즉 명령이 실행되지 않을 때 해당 값이 무엇인지 명시되어 있지 않습니다. 값이 있을 수도 있고 전혀 없을 수도 있습니다.

Q2에 대한 답변 "그렇지 않다면 위 명령 시퀀스의 동작을 어떻게 설명할 수 있습니까?" 그런 다음 논리적으로(다소 현학적으로) 따라옵니다. 값이 BASH_COMMAND정의되지 않았다는 사실로 설명됩니다 . 그 값은 정의되지 않았기 때문에 어떤 값이라도 가질 수 있으며, 이것이 바로 시퀀스가 ​​보여주는 것입니다.

추신

사양에서 실제로 취약한 지점에 도달하고 있다고 생각되는 지점이 있습니다. 당신이 말하는 곳은 다음과 같습니다.

$PROMPT_COMMAND 시작 부분에서 MYVARIABLE=$BASH_COMMAND를 수행하더라도 MYVARIABLE에는 MYVARIABLE=$BASH_COMMAND 문자열이 포함됩니다.왜냐하면 할당도 명령이기 때문입니다.

bash 매뉴얼 페이지를 읽는 방식에 이탤릭체로 표시된 부분이 사실이 아닙니다. 이 섹션에서는 SIMPLE COMMAND EXPANSION명령줄에서 변수 할당을 먼저 따로 설정한 다음

명령 이름 결과가 없으면(즉, 변수 할당만 있는 경우) 변수 할당은 현재 쉘 환경에 영향을 미칩니다.

BASH_COMMAND이는 다른 프로그래밍 언어처럼 변수 할당이 명령이 아니므로 에 표시되지 않음을 의미합니다 . 그러면 이는 또한 BASH_COMMAND=set의 출력에 본질적 set으로 set변수 할당을 위한 구문적 '마커'인 줄 이 없는 이유를 설명합니다 .

OTOH, 해당 섹션의 마지막 단락에는 다음과 같이 나와 있습니다.

확장 후 남은 명령어 이름이 있는 경우 아래와 같이 실행이 진행됩니다. 그렇지 않으면,명령종료됩니다.

... 그렇지 않은 경우를 제안하며 변수 할당도 명령입니다.

답변3

$BASH_COMMAND의 창의적인 사용

최근에 이걸 발견했어요$BASH_COMMAND의 인상적인 사용매크로와 유사한 기능을 구현할 때.

이는 별칭의 핵심 트릭이며 DEBUG 트랩 사용을 대체합니다. DEBUG 트랩에 대한 이전 게시물의 부분을 읽으면 $BASH_COMMAND 변수를 인식할 수 있습니다. 그 게시물에서 나는 DEBUG 트랩을 호출할 때마다 명령 텍스트로 설정되었다고 말했습니다. 글쎄, 모든 명령, DEBUG 트랩 또는 아니오를 실행하기 전에 설정된다는 것이 밝혀졌습니다(예: 내가 말하는 내용을 보려면 'echo "this command = $BASH_COMMAND"'를 실행하십시오). 변수를 할당함으로써(해당 라인에 대해서만) 명령의 가장 바깥쪽 범위에서 BASH_COMMAND를 캡처합니다. 여기에는 전체 명령이 포함됩니다.

저자의이전 기사또한 DEBUG를 사용하여 기술을 구현하는 동안 좋은 배경 지식을 제공합니다 trap. trap개선된 버전에서는 이 제거되었습니다.

답변4

Trap...debug의 일반적인 용도는 "screen"을 사용할 때 창 목록(^A")에 나타나는 제목을 개선하는 것입니다.

나는 "화면", "창 목록"을 더 유용하게 만들려고 노력하고 있었기 때문에 "trap...debug"를 참조하는 기사를 찾기 시작했습니다.

PROMPT_COMMAND를 사용하여 "null 제목 시퀀스"를 보내는 방법이 제대로 작동하지 않는다는 것을 발견하여 Trap...debug 방법으로 되돌렸습니다.

방법은 다음과 같습니다.

1 "shelltitle '$|bash:'"를 "$HOME/.screenrc"에 넣어 이스케이프 시퀀스를 찾도록(활성화) "screen"에 지시합니다.

2 디버그 트랩이 하위 셸로 전파되는 것을 끕니다. 이것이 활성화되면 모든 것이 엉망이 되기 때문에 중요합니다. "set +o functrace"를 사용하세요.

3 해석할 "screen"에 대한 제목 이스케이프 시퀀스를 보냅니다. Trap 'printf "\ek$(date +%Y%m%d%H%M%S) $(whoami)@$(hostname):$(pwd) ${BASH_COMMAND}\e\"' "디버그"

완벽하지는 않지만 도움이 됩니다. 이 방법을 사용하면 문자 그대로 원하는 내용을 제목에 넣을 수 있습니다.

다음 "창 목록"(5개 화면)을 참조하세요.

숫자 이름 플래그

1 bash:20161115232035 mcb@ken007:/home/mcb/ken007 RSYNCCMD="sudo rsync" myrsync.sh -R -r "${1}" "${BACKUPDIR}${2:+"/${2}" }" $ 2 bash:20161115230434 mcb@ken007:/home/mcb/ken007 ls --color=auto -la $ 3 bash:20161115230504 mcb@ken007:/home/mcb/ken007 cat bin/psg.sh $ 4 bash: 20161115222415 mcb@ken007:/home/mcb/ken007 ssh ken009 $ 5 bash:20161115222450 mcb@ken007:/home/mcb/ken007 mycommoncleanup $

관련 정보