누군가 두 명령의 출력을 파일로 다른 명령에 전달하는 방법을 물었고 그들은 다음과 같은 결과를 얻었습니다.답변다음과 같은.
( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
이걸 분해해야 해요.
some_file
에 입력으로 전달하려는 텍스트 파일이 있다고 가정해 보겠습니다 main_command
. main_command
두 개의 파일을 입력으로 사용합니다. 명령의 출력 main_command
과 함께 사용 하려면 한 가지 방법은 다음과 같습니다.some_file
cmd2
( cmd2 | ( main_command some_file /dev/fd/4 ) 4<&0 )
- 그것의 "가장 깊은" 부분(즉, 모든 것이 최고점에 도달하는 부분)은 입니다
main_command some_file /dev/fd/4
. 이것은 단지 파일some_file
및/dev/fd/4
를 인수로 전달합니다main_command
. - 이
4<&0
부분은stdin
를 가리킬 파일 설명자를 나타냅니다4
. cmd2 |
의 출력을 후속 입력과cmd2
연결합니다 .- 괄호는 무슨 뜻인지 잘 모르겠습니다. 분석 목적으로만 존재합니까, 아니면 다른 목적으로 사용됩니까?
내 질문은 다음과 같습니다
- 질문 시작 부분에 있는 명령의 압축을 어떻게 풀 수 있나요?
- 괄호는 무엇을 하는가?
- 더 간단한 명령에 대한 설명이 맞습니까?
편집: 내 논리가 맞다면 1번 대답은 필요하지 않다고 말해야겠습니다.
답변1
이것은 상당히 복잡한 명령입니다. 마지막에 귀하의 질문에 직접 답변하지만 그 전에는 unzip 명령 자체에 관한 것입니다. 가능한 한 포괄적으로 설명하려고 노력했기 때문에 일부 장소에서는 필요한 것보다 더 자세할 수도 있습니다.
( x y z )
새 셸이 현재 셸에서 생성되어 x y z
실행됨(그런 다음 현재 셸로 반환됨)을 나타냅니다. 하위 쉘은 현재 쉘의 모든 것을 상속하지만 별도의 프로세스입니다. 즉, 상위 쉘에 영향을 주지 않고 내부적으로 입력을 파이프하고 자체 환경을 변경할 수 있습니다.
열려 있는 모든 파일에는 숫자로 된 "파일 설명자"가 있습니다.와 연관되다. 이 문서의 "파일"에는 실제 파일, 소켓 및 표준 I/O 스트림을 포함한 모든 유형의 입력 또는 출력 스트림이 포함됩니다. 이 숫자는 다음과 직접 비교할 수 있습니다.C read
함수말하는 스트림을 식별하고 해당 시스템 호출과 운영 체제에서 제공하는 기타 모든 IO 기능을 사용합니다.
4<&0
리디렉션 수행표준 입력 파일 설명자(0)를 파일 설명자 4로 복제합니다.. 이것은 의미한다FD 0이 4에 복사되었습니다., 그 반대가 아니라. 이 경우 리디렉션 전에 하위 쉘의 열린 파일을 수정합니다. 현재 이것은 입력 스트림에 대한 또 다른 "이름"을 생성합니다. 그러나 중요한 부분은 이후 두 이름이 서로 독립적이라는 것입니다. FD 0이 다른 것을 참조하도록 변경되고 두 이름이 다른 경우에도 FD 4는 항상 동일한 스트림을 참조합니다.
/dev/fd/4
프로그램이 자신이 연 파일 설명자에 액세스하는 (비표준) 방법입니다.. Linux에서는 /proc/self/fd
현재 프로세스의 파일 설명자 테이블을 구체화하는 심볼릭 링크입니다 . 프로그램은 open("/dev/fd/4", O_RDONLY)
프로그램이 FD 4에서 소유한 스트림(예: 4
자체)을 참조하는 파일 핸들을 얻을 수 있습니다. 프로그램에 관한 한 이것은 다른 파일처럼 열고 닫고 읽을 수 있는 일반 파일일 뿐입니다. 열린 파일 설명자는 자식 프로세스에 의해 상속되기 때문에 main_command
하위 프로세스에 있는 파일 설명자 4와 동일한 파일 설명자 4를 가지므로 /dev/fd/4
그곳에서도 작동합니다.
cmd2 | x
cmd2
표준 출력을 실행 하고 표준 입력(또는 fd 0)에 연결합니다 x
. 명령에는 x
하위 쉘 표현식이 있습니다.
우리의 전반적인 명령
cmd2 | ( main_command /dev/fd/4 ) 4<&0
그런 다음 세 가지 주요 부분이 있습니다.
- 실행
cmd2
하고 출력을( main_command /dev/fd/4 ) 4<&0
. - 의 (표준 입력)로
4
식별된 스트림에 대해 다른 이름을 지정하십시오 .0
( main_command /dev/fd/4 )
main_command
인수로 실행하면/dev/fd/4
(아마도) 파일로 열리고 읽혀서cmd2
.
최종 효과는 Bash 프로세스 대체와 정확히 동일하게 main_command
의 출력에서 열고 읽을 수 있는 경로 이름 인수를 얻는 것 입니다 . 실제로 이것은 인수로 제공될 수 있으며 그렇지 않은 경우 내부 처리는 매우 유사합니다.cmd2
main_command <(cmd2)
/dev/fd/63
완전한 명령의 경우
( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
우리는 중첩된 하위 쉘을 가지고 있습니다. 이는 표준 입력의 복사본 두 개를 만들고 싶기 때문입니다.두 가지 다른 표준 입력: 하나는 더 큰 서브쉘로 파이프된 후 FD 3에 들어가는 의 출력이고 cmd1
, 다른 하나는 cmd2
가장 안쪽 서브쉘로 파이프된 후 FD 4에 들어가는 의 출력입니다. 두 0
명령 모두 표준 입력을 참조하지만 서로 다른 입력을 파이프했기 때문에 각 명령의 표준 입력이 다릅니다.
나는 이것이 이 질문에서 가장 혼란스러운 부분이라고 생각합니다. 모든 명령(여기서 모든 서브쉘)에는그것은cmd1
또는 에서 파이프된 표준 입력 cmd2
과 해당 고유 표준 입력 스트림은 3
또는 에 별칭이 지정됩니다 4
. 이러한 열린 파일 설명자는 다음 수준의 하위 쉘 및 하위 명령에 의해 상속되므로, /dev/fd/3
표준 입력이 이제 다른 것을 가리키더라도 가장 안쪽 명령은 외부에서 수행하는 것과 동일한 작업을 참조합니다.
외부 괄호는 일부 명령에 대해 약간 더 강력하고 좋은 습관이 될 수 있지만 반드시 필요한 것은 아닙니다. 내부적으로: 자체적인 리디렉션 세트를 가질 수 있을 뿐만 아니라 자체 표준 입력 스트림을 파이프할 수 있는 새로운 하위 프로세스를 생성하는 데 사용됩니다.
가장 안쪽 리디렉션은 실제로 중복됩니다. cmd2 | main_command /dev/fd/3 /dev/stdin
표준 입력이 더 이상 변경되지 않기 때문에 작동합니다.
문제를 직접 해결하려면:
-
질문 시작 부분에 있는 명령의 압축을 어떻게 풀 수 있나요?
지금까지의 포스팅은 언팩이 전부입니다.
-
괄호는 무엇을 하는가?
대괄호는 입력 파이핑을 포함하여 다른 명령처럼 사용할 수 있지만 내부적으로 리디렉션과 같은 일반적인 셸 작업을 수행할 수 있는 별도의 셸 프로세스인 하위 셸을 생성합니다.
-
더 간단한 명령에 대한 설명이 맞습니까?
부분적으로.
4<&0
파일 설명자 4가 stdin을 가리킬 것이라고 가정하면 중요한 것은이제 stdin이라고 함- 표준입력의 개념이 아닙니다./dev/fd/4
"모든 것이 파일 의미입니다"에서 "파일"이지만 더 구체적으로 말하면 열 때 FD 4로 돌아가는 경로 이름입니다.