bash는 복잡한 구문 없이 IO 리디렉션을 위해 tee를 사용합니다. 어떻게 작동합니까?

bash는 복잡한 구문 없이 IO 리디렉션을 위해 tee를 사용합니다. 어떻게 작동합니까?

떨어져 있는절대적인 dup(2)존재하다fd {10,11,12}에서 출력실제 사용 사례그 후 즉시 닫습니다.여기:

$ cat tags
desktop-19.9.0
foobar-1.2.3
desktop-22.9.0
mobile-24.10.0
desktop-18.9.0
desktop-21.9.0
mobile-23.10.0
foobar-1.2.4
desktop-17.8.0
desktop-20.8.0
mobile-22.9.0
desktop-16.8.0
desktop-19.8.0
mobile-21.9.0
foobar-1.2.5
desktop-15.7.0
desktop-18.7.0
mobile-20.8.0
desktop-14.7.0
desktop-17.7.0
mobile-19.8.0
desktop-13.6.0
desktop-16.6.0
mobile-18.7.0
foobar-1.2.6
desktop-12.6.0
desktop-15.6.0
mobile-17.7.0
desktop-11.5.0
desktop-14.5.0
mobile-16.6.0
desktop-10.5.0
desktop-13.5.0
mobile-15.6.0
desktop-9.4.0
desktop-12.4.0
mobile-14.5.0
desktop-8.4.0
desktop-11.4.0
mobile-13.5.0
desktop-7.3.0
foobar-1.2.7
desktop-10.3.0
mobile-12.4.0
desktop-6.3.0
desktop-9.3.0
mobile-11.4.0
desktop-5.2.0
desktop-8.2.0
mobile-10.3.0
desktop-4.2.0
desktop-7.2.0
mobile-9.3.0
desktop-3.1.0
desktop-6.1.0
mobile-8.2.0
desktop-2.1.0
desktop-5.1.0
mobile-7.2.0
desktop-1.0.0
foobar-1.2.8
desktop-4.0.0
mobile-6.1.0
cat tags        | tee  /dev/fd/{10,11,12} 10> >(
grep -w desktop | tail -n 3) 11> >(
grep -w mobile  | tail -n 3) 12> >(
grep -w foobar  | tail -n 3) 1>/dev/null

산출:

foobar-1.2.6
foobar-1.2.7
foobar-1.2.8
mobile-8.2.0
mobile-7.2.0
mobile-6.1.0
desktop-5.1.0
desktop-1.0.0
desktop-4.0.0

작동하지만 설명이 없습니다.어떻게 작동하나요?. 뒤에서 무슨 일이 일어나는가?

fd자동으로 종료되는지 모르겠습니다. 명시적인 열기/닫기를 사용하여 작성할 수 있습니까 fd?

test -e /dev/fd/10 && echo open || echo close
close

편집하다:

다음과 같이 단순화할 수 있습니다.

cat tags         | tee >(
grep -w mobile   | tail -n3) >(
grep -w desktop  | tail -n3) >(
grep -w foobar   | tail -n3) > /dev/null

시스템 호출 디버깅:

$ strace -fff -o log bash -c '
cat tags         | tee >(
grep -w mobile   | tail -n3) >(
grep -w desktop  | tail -n3) >(
grep -w foobar   | tail -n3) > /dev/null'

$ less log.*

$ grep dup log*
log.2476802:dup2(4, 1)                              = 1
log.2476803:dup2(3, 0)                              = 0
log.2476803:dup2(4, 63)                             = 63
log.2476803:dup2(4, 62)                             = 62
log.2476803:dup2(4, 61)                             = 61
log.2476803:dup2(3, 1)                              = 1
log.2476804:dup2(3, 0)                              = 0
log.2476805:dup2(4, 1)                              = 1
log.2476806:dup2(3, 0)                              = 0
log.2476807:dup2(3, 0)                              = 0
log.2476808:dup2(4, 1)                              = 1
log.2476809:dup2(3, 0)                              = 0
log.2476810:dup2(3, 0)                              = 0
log.2476811:dup2(4, 1)                              = 1
log.2476812:dup2(3, 0)                              = 0

$ LANG=C grep close log.*
log.2476801:close(3)                                = 0
log.2476801:close(4)                                = 0
log.2476801:close(4)                                = -1 EBADF (Mauvais descripteur de fichier)
log.2476801:close(3)                                = -1 EBADF (Mauvais descripteur de fichier)
log.2476802:close(4)                                = 0
log.2476802:close(3)                                = 0
log.2476802:close(1)                                = 0
log.2476802:close(2)                                = 0
log.2476803:close(3)                                = 0
log.2476803:close(4)                                = 0
log.2476803:close(3)                                = 0
log.2476803:close(4)                                = 0
log.2476803:close(3)                                = 0
log.2476803:close(4)                                = 0
log.2476803:close(3)                                = 0
log.2476803:close(3)                                = 0
log.2476803:close(3)                                = 0
log.2476803:close(3)                                = 0
log.2476803:close(3)                                = 0
log.2476803:close(3)                                = 0
log.2476803:close(3)                                = 0
log.2476803:close(3)                                = 0
log.2476803:close(3)                                = 0
log.2476803:close(4)                                = 0
log.2476803:close(5)                                = 0
log.2476803:close(0)                                = 0
log.2476804:close(63)                               = 0
log.2476804:close(4)                                = -1 EBADF (Mauvais descripteur de fichier)
log.2476804:close(3)                                = 0
log.2476804:close(3)                                = -1 EBADF (Mauvais descripteur de fichier)
[...]

관련된:http://mywiki.wooledge.org/ProcessSubstitution

답변1

당신이 글을 쓸 때tee /dev/fd/{10,11,12} 10> (…) 11> (…) 12> (…)

쉘은 먼저 파이프를 생성하고, 파이프를 상속하는 하위 프로세스를 생성하고, 사용되지 않는 파이프 끝을 닫고 파일 디렉터리를 다시 매핑합니다. 그런 다음 명령이 실행되면 /dev/fd/10(또는 11 또는 12)을 열 수 있습니다.

커널은 사용 가능한 파일 설명자만 표시합니다. 리디렉션 의 범위는 10>해당 명령으로 제한됩니다.

strace보여주고 싶다면 예를 들어 dup2보는 것이 좋습니다 .strace -ff bash -c "cmd1 >(cmd2)" 2>&1 | grep dup

관련 정보