`bash -c "$cmd"`가 여기서 현재 날짜를 반환하는 이유는 무엇입니까?

`bash -c "$cmd"`가 여기서 현재 날짜를 반환하는 이유는 무엇입니까?

문맥:https://stackoverflow.com/a/372​53784/15603477

cmd='printf "%s\n" "$(date -d "$variable" +%c)"'
echo ${variable}

반품2010-09-08 12:34:56

echo "$cmd"반품 printf "%s\n" $(date -d "$variable")
echo "${cmd}"반품printf "%s\n" $(date -d "$variable")

bash -c "$cmd" 그런 다음 답변에 표시된 대로 다음 명령을 실행합니다 .

Fri
Dec
24
00:00:00
IST
2021

발견된 내용은 다음과 같습니다.

옵션이 아닌 첫 번째 인수 command_string에서 명령을 읽고 실행한 후 종료합니다. command_string 뒤에 인수가 있는 경우 첫 번째 인수는 $0에 할당되고 나머지 인수는 위치 인수에 할당됩니다. $0에 대한 지정은 경고 및 오류 메시지에 사용되는 쉘의 이름을 설정합니다.


내 질문은 마지막 명령 bash -c "$cmd", 출력에 관한 것입니다.오늘(현재 2021년 12월 24일입니다.) 어디서 오셨나요?

--업데이트: 확인했습니다.https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#eval,https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Bourne-Shell-Builtins,https://man7.org/linux/man-pages/man1/bash.1.html 다음 인용문은 내가 찾은 것입니다.eval

eval [arg ...] 인수를 읽고 이를 단일 명령으로 연결합니다. 그런 다음 쉘은 명령을 읽고 실행하며 해당 종료 상태는 eval 값으로 반환됩니다. 만약에

답변1

쉘 코드는 3개의 매개변수를 사용하여 명령을 bash -c "$cmd"실행합니다 .bash

  1. bash
  2. -c
  3. $cmd가변 내용

bash이러한 쉘을 호출하는 것은 세 번째 인수의 코드를 해석하는 표준 방법입니다(단지 1이 아닌 모든 쉘이 이를 수행함).

$cmd여기서는 다음과 같이 초기화된다고 말합니다 .

cmd='printf "%s\n" "$(date -d "$variable" +%c)"'

그러나 출력에는 다음 echo "$cmd"과 같이 할당된 것으로 표시됩니다.

cmd='printf "%s\n" $(date -d "$variable" +%c)'

따라서 새 호출에 의해 해석될 쉘 코드는 다음 bash과 같습니다.

printf "%s\n" $(date -d "$variable" +%c)

이제 bash새로운 통역사가 시작되므로 $variable거기에 할당되지 않습니다. 대신 bash -uc( 와 동일 bash -o nounset -c)을 실행하면 -c다음을 얻게 됩니다.

bash: line 1: variable: unbound variable

nounset옵션이 없으면 설정되지 않은 변수는 마치 비어 있는 것처럼 확장되므로 date다음 인수를 사용하여 명령을 호출하십시오.

  1. date
  2. -d
  3. 공리
  4. +%c

-d표준 date옵션이 아닙니다. GNU의 경우 date입력 날짜를 지정하는 데 사용됩니다. 입력 날짜가 비어 있으면 date -d 0또는 date -d 00:00:00, 즉 오늘 아침 00:00:00 과 같습니다 .

이제 $(date...)참조가 없고 목록 컨텍스트( printf명령 인수)에 있기 때문에 분할+glob의 영향을 받습니다. 분할 부분은 공백, 탭 및 개행 문자가 포함된 bash의 기본 날짜 출력을 중단하므로 출력에서 ​​공백으로 구분된 각 단어에 대해 생성된 별도의 인수를 $IFS볼 수 있습니다 (와일드카드 부분은 여기서 아무 작업도 수행하지 않습니다. ) 출력에는 와일드카드 문자가 없습니다 .printfdatedate

따라서 date다음을 출력 하면 다음 매개변수가 포함된 호출이 Fri Dec 24 00:00:00 IST 2021발생합니다 .printf

  1. printf
  2. %s\n
  3. Fri
  4. Dec
  5. 00:00:00
  6. IST
  7. 2021

모든 인수를 사용하기 위해 가능한 한 여러 번 형식을 printf재사용 하고 결국 모든 인수를 별도의 줄에 인쇄합니다.%s\n

bash이제 이 새 인스턴스를 원한다면상속하다이를 호출하는 셸 의 경우 나중에 호출하는 각 명령에 대한 환경에 이 변수를 추가 $variable할 수 있습니다 .export

export variable
bash -c "$cmd"

( printenv variable, perl -E 'say $ENV{variable}'...도 볼 수 있습니다).

또는 bash³를 한 번만 호출하려면 다음을 수행하세요.

(export variable; exec bash -c "$cmd")

또는:

variable=$variable bash -c "$cmd"

존재하다

eval "$cmd"

현재 셸에는 해석의 코드가 전달되며 $cmd이는 호출 내에서 디스패치된 셸이므로 $variable해당 내용에 액세스할 수 있으므로 환경으로 내보낼 필요가 없습니다.


¹ 이는 실제로 쉘 언어로 간주될 수 없는 다른 언어에 대한 일부 통역사의 경우에도 해당됩니다. python예를 들어 일부는 다른 옵션을 사용합니다(예: sed -e 'sed code', perl -e 'perl code', php -r 'php code'... 또는 전혀 옵션 없음) awk 'awk code'.sed 'sed code'

² 및 $0는 로 설정되어 bash있으며 여기의 위치 매개변수 목록은 비어 있습니다.

bash3 및 인스턴스가 자체적으로 실행할 명령

답변2

이 변수로 정의된 명령은 $cmd이름이 지정된 변수를 참조합니다 $variable. $cmd다른 프로세스의 새 쉘 호출로 전달되는 경우 $cmd이 변수는 실행 시 설정되지 않습니다. 따라서 날짜 가져오기 호출의 결과는 date -d "" +%c현재 날짜를 반환한다는 것입니다.

코딩 관점에서 명령을 변수에 저장하는 것은 나쁜 습관입니다. 너~ 할 것이다조만간 당신은 인용의 악몽에 빠지게 될 것입니다. 변수를 데이터로, 함수를 코드로 사용하세요.

cmd() {
    local v=$1
    printf "%s\n" "$(date -d "$v" +%c)"'
}

variable="2010-09-08 12:34:56"
cmd "$variable"

마지막으로, 타당한 이유가 없는 한 변수를 사용할 때 항상 큰따옴표로 묶어야 합니다. ( echo $variable나쁨, echo "$variable"더 좋음, printf "%s\n" "$variable"최고.)

관련 정보