쉘 프로그래밍, 임시 파일 피하기

쉘 프로그래밍, 임시 파일 피하기

나는 종종 동일한 패턴을 따르는 KSH 쉘 스크립트를 작성합니다.

  • (1) 하나 이상의 명령 출력 검색
  • (2) grep|cut|awk|sed를 사용하여 포맷하고 화면이나 파일에 인쇄합니다.

이를 위해 나는 종종 (1)의 출력을 임시 파일에 저장한 다음 (2)와 같이 파일 형식을 지정합니다.

다음 코드를 예로 들어 보겠습니다.

TMPFILE=file.tmp

# If tmpfile exists rm it.
[ -f $TMPFILE ] && rm -f $TMPFILE

for SERVICE in $(myfunc); do
    getInfo $SERVICE > $TMPFILE # Store raw output in the TMPFILE

    # I retrieve the relevant data from the TMPFILE
    SERV_NAME=$(head -1 $TMPFILE | sed -e 's/ $//')
    SERV_HOSTNAME=$(grep HOSTNAME $TMPFILE | cut -d "=" -f2)
    SERV_ARGS=$(grep Arguments $TMPFILE | cut -d ":" -f2)

    print $SERV_NAME $SEP $SERV_HOSTNAME $SEP $SERV_ARGS
    rm -f $TMPFILE #rm the TMPFILE in vue of next iteration
done

매번 파일을 디스크에 쓰지 않도록 파이프, 리디렉션 등을 사용하는 방법이 있습니까?

도움이 된다면 ksh 버전 M-11/16/88i를 사용하고 있습니다.

답변1

귀하의 코드가 임시 파일을 완벽하게 합법적으로 사용하고 있는 것 같습니다. 저는 이 방법을 고수하겠습니다. 정말로 변경해야 할 유일한 것은 임시 파일이 생성되는 방식입니다. 다음과 같은 것을 사용하십시오

 TMP=$(tempfile)

또는

 TMP=$(mktemp)

아니면 적어도

 TMP=/tmp/myscript_$$

이렇게 하면 이름을 쉽게 예측할 수 있고(안전하게) 동시에 실행되는 여러 스크립트 인스턴스 간의 간섭을 배제할 수 없습니다.

답변2

변수를 사용할 수 있습니다.

info="$(getInfo $SERVICE)"
SERV_NAME="$(head -1 $TMPFILE <<<"$info" | sed -e 's/ $//')"
...

에서 man ksh:

<<<word       A  short  form of here document in which word becomes the
              contents of the here-document after any parameter  expan-
              sion,  command  substitution, and arithmetic substitution
              occur.

장점은 다음과 같습니다:

  • 병렬 실행을 활성화합니다.
  • 내 경험상 이것은 임시 파일보다 훨씬 빠릅니다. 데이터가 너무 많아서 교체가 필요할 정도가 아니라면 속도는 훨씬 더 빨라야 합니다(작은 데이터 크기의 경우 더 빠를 수 있는 HD 캐시 버퍼만 제외).
  • 다른 프로세스나 사용자가 귀하의 데이터를 망칠 수 없습니다.

답변3

두 가지 옵션이 있습니다:

  1. 데이터를 한 번(예제에서 getInfo) 검색하여 파일에 저장합니다.

  2. 데이터는 매번 가져오며 로컬에 저장되지 않습니다. 즉, getInfo호출될 때마다

재처리/다시 가져오기를 방지하기 위해 임시 파일을 생성하는 데 문제가 없습니다.

임시 파일을 어딘가에 남겨두는 것이 걱정된다면 trap스크립트가 종료/중단되는 경우 항상 삭제했는지 확인하는 데 사용할 수 있습니다.

trap "rm -f $TMPFILE" EXIT HUP INT QUIT TERM

mktemp임시 파일의 고유한 파일 이름을 만드는 데 사용됩니다 .

답변4

파일을 생성하는 대신 쉘 할당문을 구성하고 출력을 평가합니다.

for SERVICE in $(myfunc); do
    eval $(getInfo $SERVICE |
               sed -n -e '1/\(.*\) *$/SERV_NAME="\1"/p' \
                   -e '/HOSTNAME/s/^[^=]*=\([^=]*\).*/SERV_HOSTNAME="\1"/p' \
                   -e '/Arguments/^[^:]*:\([^:]*\).*/SERV_ARGS="\1"/p')
    print $SERV_NAME $SEP $SERV_HOSTNAME $SED $SERV_ARGS
done

또는 정보만 인쇄하려는 경우:

for SERVICE in $(myfunc); do
    getInfo $SERVICE | awk -vsep="$SEP" '
        BEGIN{OFS=sep}
        NR == 1 { sub(/ *$/,""); SERV_NAME=$0 }
        /HOSTNAME/ { split($0, HOST, /=/; SERV_HOSTNAME=HOST[2]; }
        /Arguments/ { split($0, ARGS, /:/; SERV_ARGS }
        END { print SERV_NAME, SERV_HOSTNAME, SERV_ARGS }'
done

관련 정보