파일을 입력으로 사용하여 다양한 작업을 수행하는 대규모 스크립트가 있습니다. 이것은 테스트 버전입니다:
echo "cat: $1"
cat $1
echo "grep: $1"
grep hello $1
echo "sed: $1"
sed 's/hello/world/g' $1
내 스크립트에서 프로세스 대체를 사용할 수 있기를 원하지만 첫 번째 명령( cat
)만 작동하고 나머지는 작동하지 않습니다. 파이프라인이기 때문인 것 같아요.
$ myscript.sh <(echo hello)
다음을 인쇄해야 합니다:
cat: /dev/fd/63
hello
grep: /dev/fd/63
hello
sed: /dev/fd/63
world
가능합니까?
답변1
이 <(…)
구성은 파이프를 생성합니다. 파이프는 유사한 filename 을 통과 /dev/fd/63
하지만 이는 특별한 유형의 파일입니다. 실제로 파이프를 여는 것은 파일 설명자 63을 복사하는 것을 의미합니다. (끝 참조이 답변더 많은 설명을 원하시면. )
파이프에서 읽는 것은 파괴적인 작업입니다. 일단 바이트를 캡처하면 다시 되돌릴 수 없습니다. 따라서 스크립트는 파이프의 출력을 저장해야 합니다. 임시 파일(입력이 큰 경우 선호) 또는 변수(입력이 작은 경우 선호)를 사용할 수 있습니다. 임시 파일 사용:
tmp=$(mktemp)
cat <"$1" >"$tmp"
cat <"$tmp"
grep hello <"$tmp"
sed 's/hello/world/g' <"$tmp"
rm -f "$tmp"
(두 호출을 cat
로 결합할 수 있습니다 tee <"$1" -- "$tmp"
.) 변수 사용:
tmp=$(cat)
printf "%s\n"
printf "%s\n" "$tmp" | grep hello
printf "%s\n" "$tmp" | sed 's/hello/world/g'
명령 대체는 $(…)
명령 출력 끝에 있는 줄 바꿈을 잘라냅니다. 이를 방지하려면 추가 문자를 추가한 다음 제거하세요.
tmp=$(cat; echo a); tmp=${tmp%a}
printf "%s\n"
printf "%s\n" "$tmp" | grep hello
printf "%s\n" "$tmp" | sed 's/hello/world/g'
그런데,변수 대체에 대한 큰따옴표를 잊지 마십시오.
답변2
파일 작업을 할 때 해당 데이터를 여러 번 읽을 수 있습니다. 명명된 파이프(실제로 프로세스 대체를 통해 생성됨)를 사용하는 경우 한 번만 읽을 수 있습니다. 따라서 grep
및 sed
명령은 빈 입력을 받습니다.
(파이프라인을 이해하는 방법잘 읽어보시면 좋을 것 같습니다. )
프로세스 교체를 위해 다음과 같이 작성할 수 있습니다.
cat $1 | tee >(echo "cat: $1"; cat) | tee >(echo "grep: $1"; grep hello) | (echo "sed: $1"; sed 's/hello/world/g')
하지만 이 경우 두 번째 cat
와 grep
두 sed
번째는 병렬로 실행되고 출력이 인터리브됩니다. 이것이 더 유용할 수 있습니다:
cat $1 | tee >(cat > cat.txt) | tee >(grep hello > grep.txt) | sed 's/hello/world/g' > sed.txt
답변3
일반적인 접근 방식은 $1
매개변수를 선택적으로 만드는 것입니다. 그런 다음 FILE=${1-/dev/stdin}
여러 번 정의하고 사용할 수 있습니다 . FILE
그러나 파이프에 대한 다중 읽기는 순차적으로 읽혀지며 데이터는 반복되지 않습니다.
이 문제를 해결하는 가장 쉬운 방법은 임시 파일을 사용하는 것입니다.
if [ -z "$1" ] ; then FILE=$(mktemp); cat >FILE; else FILE=$1; fi
일부 파일 이름을 명시적으로(결국) 전달하려면 /dev/fd/x
동일한 임시 파일 트릭을 사용할 수 있습니다.
FILE=$(mktemp); cat "$1" >FILE
tee
복잡한 방법을 사용하여 stdin 파일 설명자의 입력을 여러 다른 파일 설명자로 복사할 수도 있습니다 . 그러나 결국 이 방법은 매우 번거로울 수 있습니다.
답변4
프로세스 대체를 통해 얻은 I 파일은 기본 구현에 따라 검색할 수 없으므로 여러 번 읽을 수 없습니다.