두 가지 다른 결과를 제공하는 아래 두 줄을 살펴보겠습니다.
p=$(cd ~ && pwd) ; echo $p
p=$(cd ~ | pwd) ; echo $p
둘 사이의 차이점은 무엇입니까?
답변1
존재하다 p=$(cd ~ && pwd)
:
명령 대체,
$()
서브셸에서 실행cd ~
~
디렉토리를 (홈 디렉토리) 로 변경 하고cd
성공하면(&&
) 저장된 문자열이 홈 디렉토리가 되도록pwd
STDOUT에 디렉토리 이름을 인쇄합니다 .p
/home/foobar
존재하다 p=$(cd ~ | pwd)
:
서브쉘을 다시
$()
생성양쪽의 명령은
|
자체 서브셸에서 실행됩니다(둘 다 동시에 시작됩니다).이는 서브쉘 에서
cd ~
수행되며pwd
분리서브쉘pwd
따라서 명령을 실행한 위치의 STDOUT만 가져올 수 있습니다. 이는 상상할 수 있는 모든 디렉터리일 수 있으므로p
홈 디렉터리가 아닌 명령이 호출된 디렉터리의 이름을 포함합니다.
답변2
핵심 문제는 연산자를 두 명령 &&
에 연결하는 방법입니다.|
종료 코드로 명령을 연결합니다 &&
. |
파일 설명자(stdin, stdout)를 통해 두 명령을 연결합니다.
먼저 단순화해 보겠습니다. 할당을 제거하고 다음과 같이 작성할 수 있습니다.
echo $(cd ~ && pwd)
echo $(cd ~ | pwd)
분석을 위해 명령 실행 서브셸을 제거할 수도 있습니다.
$ cd ~ && pwd
$ cd ~ | pwd
&&
예를 들어 명령이 실행되는 디렉터리를 표시하도록 프롬프트를 변경하면 PS1='\w\$ '
다음이 표시됩니다.
/tmp/user$ cd ~ && pwd
/home/user
~$
- 이 명령은
cd ~
"현재 디렉터리"를 명령을 실행하는 실제 사용자의 홈 디렉터리로 변경합니다(/home/user
). - 명령의 결과는 성공(종료 코드 0)이므로 && 이후의 다음 명령이 실행됩니다.
- "현재 작업 디렉토리"를 인쇄합니다.
- 의 프롬프트에 표시된 대로 실행 중인 셸이
pwd
로 변경되었습니다 .~
~$
어떤 이유로(디렉터리가 존재하지 않고, 권한이 디렉터리 읽기를 방해함) 디렉터리 변경이 실패하면(종료 코드가 0이 아님) 다음 명령이 실행되지 않습니다.
예:
/tmp/user$ false && pwd
/tmp/user$ _
종료 코드 1은 false
다음 명령의 실행을 방지합니다.
따라서 "Command 1"의 종료 코드는 "Command 2"에 영향을 미칩니다.
이제 전체 명령의 효과는 다음과 같습니다.
/tmp/user$ echo $(cd ~ && pwd)
/home/user
/tmp/user$ _
디렉토리가 변경되었지만 서브쉘 내에서는 $(…)
변경된 디렉토리가 인쇄되지만 /home/user
서브쉘이 닫히자마자 삭제됩니다. pwd는 초기 디렉터리( /tmp/user
)로 돌아갑니다.
|
무슨 일이 일어나는가?
/tmp/user$ cd ~ | pwd
/tmp/user
/tmp/user$ _
메타 문자 |
(실제 연산자가 아님)는 쉘에 소위 "파이프"를 생성하도록 지시합니다. (bash에서) |
파이프 양쪽의 각 명령( )은 오른쪽 명령으로 시작하여 각 하위 쉘 내에 설정됩니다. 그러면 왼쪽에 명령어가 있습니다. /dev/stdin
오른쪽 명령의 입력 파일 설명자( )가 출력 설명자( /dev/stdout
)에 연결되어 두 명령이 시작되어 상호 작용합니다. 왼쪽 명령( cd -
)은 출력이 없고 오른쪽 명령( pwd
)은 입력을 허용하지 않습니다. 따라서 각 셸은 자체 하위 셸 내에서 독립적으로 실행됩니다.
cd ~
쉘의 비밀번호를 변경하십시오 .pwd
다른 서브쉘의 (완전히 별도의) 비밀번호를 인쇄합니다 .
파이프라인이 종료되면 각 셸의 변경 사항이 삭제되고 외부 하위 셸에는 pwd 변경 사항이 없습니다.
이것이 바로 이 두 명령이 "파일 설명자"를 통해서만 연결되는 이유입니다.
이 경우 아무 것도 전송되지 않고 아무것도 읽혀지지 않습니다.
전체 명령은 다음과 같습니다.
$ echo "$(cd ~ | pwd)"
명령이 실행된 디렉토리만 인쇄됩니다.
답변3
두 번째 경우에는 "|"을 의미하는지 잘 모르겠습니다.
'|' 셸에서 한 명령의 출력을 다른 명령의 입력으로 파이프합니다. 일반적인 사용 사례는 다음과 같습니다.
curl http://abcd.com/efgh | grep ijkl
하나의 명령을 실행한 다음 다른 명령을 사용하여 명령의 출력을 처리합니다.
제시한 예에서 "cd"는 일반적으로 출력을 생성하지 않는 반면 "pwd"는 입력을 필요로 하지 않기 때문에 이것은 다소 의미가 없습니다.
'&&' 및 '||'는 파트너 명령에 지나지 않습니다. 논리 AND 및 OR 연산자가 대부분의 언어에서 사용되는 것과 동일한 방식으로 설계되었습니다. 그러나 수행된 최적화는 특정 동작, 즉 쉘 프로그래밍 패러다임을 제공합니다.
논리적 AND 연산의 결과를 확인하려면 첫 번째 조건이 성공하면 두 번째 조건을 평가하기만 하면 됩니다. 첫 번째 조건이 실패하면 전체 결과는 항상 false가 됩니다.
논리적 OR 연산의 결과를 확인하려면 첫 번째 조건이 실패할 때 두 번째 조건을 평가하면 됩니다. 첫 번째 조건이 성공하면 전체 결과는 항상 true가 됩니다.
따라서 셸에서는 완료되어 성공적인 결과 코드를 반환하는 경우 command1 && command2
command2
에만 실행됩니다 . command1
있는 경우 command1 || command2
command2
완료 시 실행되며 command1
, command1
그렇다면 실패 코드를 반환합니다.
또 다른 일반적인 예는 command1
테스트 명령입니다. 이는 단일 줄의 if/then 문을 생성합니다. 예를 들면 다음과 같습니다.
[ "$VAR" = "" ] && VAR="Value if empty"
이는 변수가 현재 비어 있는 경우 변수에 값을 할당하는 (장황한) 방법입니다.
Stack Exchange의 다른 곳에서도 이 프로세스를 사용하는 예가 많이 있습니다.