다음과 같은 루틴을 고려해보세요:
alpha() { echo a b c |tr ' ' '\n'; }
paste
스트림을 출력하고 출력 스트림을 가져와 변환한 다음 원래 출력 스트림과 함께 사용하고 싶습니다 .
예를 들어 upcasing을 사용하여 변환하면 다음과 같이 원하는 것을 얻을 수 있습니다.
$ mkfifo p1 p2
$ alpha | tee p1 >( tr a-z A-Z > p2) >/dev/null &
$ paste p1 p2
a A
b B
c C
제 질문은 이 작업을 수행하는 더 좋은 방법이 있습니까? 가급적이면 명명된 파이프를 포함하지 않는 방법이 있습니까?
답변1
대부분의 unice에서는 장치 링크를 통해 파일 설명자를 참조할 수 있습니다.
alpha(){ echo a b c | tr \ \\n; }
alpha | { alpha |
tr \[:lower:] \[:upper:] |
paste - /dev/fd/9
} 9<&0
A a
B b
C c
명명된 파이프
글쎄요, 이미 잘 작동하는 버전이 있습니다. 내 편집기에서 열린 버전(완료되지 않음)현재로서는 실현 가능하지 않습니다. 전체 옵션을 여러 조각으로 분석했으며 내 의도만 막연하게 기억하고 있습니다. 하지만 이것은...
_p(){ : "$((_$$=0))"
cd -P -- "${TMPDIR:-/tmp}" &&
while [ -h "$$.$((_$$+=$$))" ] ||
[ -e "$$.$((_$$))" ]
do :; done &&
mkfifo -m a-w,u=rwx "$$.$((_$$))" &&
printf %s "$PWD/$$.$((_$$))" &&
exec >&- >&0 &&
case $1 in
(+) shift
eval " rm $$.$((_$$))
cd - >/dev/null
$@" < "$$.$((_$$))" &;;
(-) shift
eval " rm $$.$((_$$))
cd - >/dev/null
$@" > "$$.$((_$$))" &;;
(*) set --
: "${1:?"USAGE: [-+] [cmd args...]"}"
esac
} <&- <>/dev/null
당신은 매우 이상한 일이 일어나고 있음을 발견할 수 있습니다 $((_$$))
. 이는 가능한 한 명령 환경에 개입하지 않으려는 방법입니다. 난 여기를 유지하려고 정말 열심히 노력하고 있어모두함수의 목적은 프로세스 교체와 동일한 작업을 수행하는 것이므로 가능한 환경 값은 내가 만들 수 있는 만큼 원시적입니다. 파이프에 작성된 임의의 명령을 실행합니다.
cat "$(_p - echo a b c)"
a b c
다음은 워크플로의 단순화된 버전입니다.
mkfifo pipe # make a pipe
printf %s\\n "$PWD/pipe" # substitute its file name
exec <&- </dev/null >&- >/dev/null # break cmd sub i/o
eval "rm pipe;$@" >pipe & # eval rm; args
이 eval
명령은 모든 인수를 단일 명령으로 래핑하기 때문에 eval
stdout은 eval
전체 'd 명령 그룹의 표준 출력입니다. 이것은껍데기이는 단순히 표준 출력으로 상속하는 하위 프로세스가 아닌 해당 파이프 설명자를 소유합니다. 그래서 쉘은 그렇게 했습니다 open()
. 왜냐하면 우리가 그랬기 때문입니다.차단하다 open()
( >
대신에 좋아요 <>
)파이프가 판독기를 얻을 때까지 쉘이 정지됩니다.
이는 rm
다른 프로세스가 파이프에 대한 읽기 파일 설명자를 설정할 때까지 실행이 없음을 의미합니다. 일부 프로세스가 읽기 위해 열 때(상술 한 바와 같이 cat
)rm
케이싱이 더 이상 매달리지 않고 취해지는 첫 번째 조치 는 다른 조치를 취하기 전에 파이프가 "d"가 되는 것입니다 . 이것은아니요문제 - 파이프라인이미리더 프로세스와 라이터 프로세스가 있습니다. 모두 괜찮습니다.
이건 좀 귀찮습니다. 예를 들어:
echo "$(_p -)"
/tmp/6023.6023
^저것파이프는 'd'되지 않습니다 rm
. echo
읽지 마세요. 그래서 eval
아직도 기다리고 있어요. 죽여:
: </tmp/6023.6023
...하지만 죽이기에는 충분합니다.
내가 사용하는 용도는 다음과 같습니다.
exec 9<> "$(_p -)"
sed -ue's/sed/mikeserv/' <&9 &
echo hi sed >&9
hi mikeserv
<()
그런데, 나는 동등한 것만 보여줬 지만, >()
이렇게 시뮬레이션할 수 있습니다...
echo hi sed >"$(_p + sed -e's/sed/mikeserv/' '>&2')"
hi mikeserv
기타 파이프라인
이 작업을 수행하려면 내 해킹 기능이 필요하지 않습니다. 프로세스 대체는 매우 일반적입니다. 아무것도 당신을 막을 수 없습니다유지하다파이프가 필요할 때 즉시 할당하고 폐기할 필요가 없습니다.
(편집증 참고: 이 파일이 어디에 있는지 모르기 때문에 좀 싫습니다.~에서- 아마도 당신은 더 적응력이 있는 사람이므로 다음 사항을 받아들일 수 있습니다)
eval "exec 9<> " <(:)
파이프가 있습니다 - 그것은 모두 당신 것입니다. 정리가 필요하지 않습니다. 이제 가셔도 됩니다.
_pp
- 헤헤
_pp(){ : "$((_$$=0))"
_e() case ${1:-0} in
(i|0) exec >&- 1<>/dev/null;;
(o|1) ! exec <&- <>/dev/null;;
(e|[2-9])
exec <&- <>/dev/null >&- >&0
set "${1#e}"
return "${1:-2}";;
(*[\<\>]*)
eval "
exec <&- <>/dev/null >&- >&0 $1"
esac
cd -P -- "${TMPDIR:-/tmp}" &&
while [ -h "$$.$((_$$+=1))" ] ||
[ -e "$$.$((_$$))" ]
do :; done &&
mkfifo -m a-w,u=rwx "$$.$((_$$))" &&
printf "%s/%s" "$PWD" "$$.$((_$$))" &&
case $1 in
(+*) set \> \< "$@" ;;
(-*) set \< \> "$@" ;;
(*) rm "$$.$((_$$))"
set '' USAGE: '<-+>[+-[fd][file]]'
${1:?"$(printf "\n%s\t%s [cmd...]$@")"};;
esac &&
case $3 in
(?|?[ioe0-9])
_e "${3#?}"
eval "exec $1&$?";;
(?/*) _e "$1"'"$2"' "${3#?}";;
(*) _e "$1"'"$2"' "$OLDPWD/${3#?}"
esac &&
eval " shift 3
eval \" rm $$.$((_$$))
cd - >/dev/null
\$@\" $2$$.$((_$$)) &"
}
_p
...그래서...드디어 나랑 하기 시작했어피작동하는 것으로 입증되었습니다. 이러한 [-+]
옵션은 무엇이든 취할 수 있습니다.ioe
옵션의 의미std(in|out|err)
( stdout
명령 서브루틴에서는 거의 쓸모가 없지만)또는[0-9]
설정한 설명자나 임의의 파일 이름으로 해석되는 모든 것을 참조하세요. 인수를 사용하여 호출하면 +
입력이 호출하는 명령에서 나와야 하므로 출력 스트림이 이해되고 -
인수가 입력으로 사용됩니다.
따라서 sed
위의 마지막 내용은 다음과 같이 작성될 수 있습니다.
echo hi sed >"$(_pp +2 sed s/sed/mikeserv/)"
hi mikeserv