シェルプログラミング、一時ファイルを避ける

シェルプログラミング、一時ファイルを避ける

私はしばしば同じパターンに従うKSHシェルスクリプトを書いています。

  • (1) 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

2つのオプションがあります。

  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

関連情報