다음은 "두 번 스크립팅"이 의미하는 매우 간단한 예입니다.
#!/bin/bash
INPUTFILE=$1
grep '^#' "$INPUTFILE"
grep -v '^#' "$INPUTFILE" | sort
스크립트(라고 부르겠습니다)는 twopass.sh
파일 경로를 유일한 인수로 사용합니다. 그런 다음 먼저 로 시작하는 모든 줄을 원래 순서대로 인쇄합니다 INPUTFILE
. 둘째, 인쇄됩니다.INPUTFILE
#
정렬순으로내부의 모든 라인이 INPUTFILE
완료되었습니다.아니요첫 번째 #
.
예를 들어 파일에 example.txt
다음 줄이 포함되어 있는 경우
# foo comes first
# bar comes second
# baz comes third
wobble
quux
wibble
frobozz
...그런 다음 twopass.sh
스크립트를 적용하면 다음과 같은 결과가 생성됩니다.
% ./twopass.sh example.txt
# foo comes first
# bar comes second
# baz comes third
frobozz
quux
wibble
wobble
이 스크립트를 수정하려면 어떻게 해야 합니까?반품stdin
에 대해서도 같은 작업을 수행합니까?
즉, 필요한 새 버전의 스크립트를 사용하면 다음 줄은 위에 표시된 것과 동일한 출력을 생성해야 합니다.
./twopass.sh < example.txt
나는 이 질문에 대한 답변에 매우 bash
관심이 있습니다 zsh
.
답변1
일반적인 경우 stdin을 여러 번 처리하려면 첫 번째 읽기 후 다시 읽을 수 있도록 역추적할 수 있어야 합니다(파이프, 소켓, 터미널 등 모든 유형의 파일에서는 가능하지 않음). 또는 입력을 여러 번 읽을 수 있는 일반 파일이나 메모리에 저장하세요.
내장된 검색 및 임시 파일 관리 지원(예: zsh 또는 ksh93)이 있는 셸을 사용하는 것이 더 쉽습니다.
#! /bin/zsh -
zmodload zsh/system || exit
if (($#)); then
# arguments are provided. They are assumed to be file arguments
# to process (use ./- for the file called -)
grep -h -- '^#' "$@"
grep -vh -- '^#' "$@" | sort
else
# process stdin
if (( (pos = systell(0)) >= 0 )); then
# input is seekable
grep '^#'
sysseek $pos || {
syserror -p "Cannot go back: "
exit 1
}
grep -v '^#' | sort
else
# not seekable, store input in a temporary file using =(cat)
() {
grep -- '^#' $1
grep -v -- '^#' $1
} =(cat)
fi
fi
( -h
출력 파일 이름을 건너뛰는 것은 GNU grep
확장 이므로 grep
지원하지 않는 경우 해당 확장으로 바꿀 수 있습니다 cat -- "$@" | grep ...
.)
bash
임시 파일을 찾거나 생성하는 기능은 지원되지 않지만 , 또는 / 를 호출하도록 zsh
할 ksh93
수 perl
있습니다 python
.
그러나 특정 사용 사례의 경우 다음과 같이 수행할 수도 있습니다.
#! /bin/sh -
gawk -e '
/^#/ {print; next}
{print | "sort"}' -E /dev/null "$@"
-e
+이 트릭을 -E
사용하려면 문자가 포함된 파일 이름을 처리할 수 있어야 합니다 =
( -
인수는 여전히 gawk
이름이 지정된 파일이 아니라 stdin을 의미하는 것으로 해석됩니다 -
).
위에 정렬된 출력 표시 보장뒤쪽에sort
읽어야 할 댓글모두출력을 시작하기 전에 입력합니다. sort
데이터를 메모리나 임시 파일에 저장합니다.
아래와 같은 방법:
#! /bin/zsh -
{ cat -- "$@" > >(grep '^#' 4>&1 >&3) | grep -v '^#' | sort; } 3>&1
또는 ksh93 또는 bash와 호환됩니다.
{
cat -- "$@" |
{ tee >(grep '^#' 4>&1 >&3); } |
grep -v '^#' |
sort
} 3>&1
출력은 둘 다에 적용 cat
되며 작동해야 합니다 . 쓰기가 완료될 때까지 출력이 시작되지 않도록 보장 하는 데 사용됩니다 (런타임에도 파이프를 열어두기 때문).tee
grep
grep -v | sort
4>&1
sort
grep
grep -v
답변2
sort
정렬하려는 출력 부분 만 해당됩니다 .grep -E '^#' "$INPUTFILE";(grep -E -v '^#' "$INPUTFILE" | sort )