他のスクリプトの一時ファイルライフサイクルを処理するために再利用可能なスクリプトを設計する方法

他のスクリプトの一時ファイルライフサイクルを処理するために再利用可能なスクリプトを設計する方法

別の(「アプリケーション」)スクリプトの一時ファイルを使用して、ワークセット全体を処理する再利用可能な(「ユーティリティ」)スクリプトを作成する必要があります。

  1. 作る
  2. 生成された一時ファイルを追跡します。
  3. 終了(定期的なユーザーの完了と中断)をキャプチャし、生成されたすべてのアイテムを削除します。

各アプリケーションスクリプトは、使用するすべてのサブスクリプトに対して一度呼び出すいくつかの「デフォルト」スクリプトに依存するのではなく、ユーティリティスクリプト自体を「含める」必要があります。

重要な要件は、ユーティリティスクリプトを使用するアプリケーションスクリプトが互いに呼び出すことができ、各スクリプトが順番に一時ファイルを使用する必要があることです。スクリプト間のすべての呼び出しは

./some_script.sh

そして

. ./some_script.sh

一部のスクリプトはエラーコードで終了し、他のスクリプトは明示的に終了しませんexit。アプリケーションスクリプト自体は、サブシェルを使用してコマンドラインから呼び出すことができます。たとえば、次のようになります。

echo "Parameter" |
./feed_parameter_to_script.sh script_using_tmps.sh

理想的には、アプリケーションスクリプトは独自のコードでサブシェルから一時ファイルの生成を呼び出すことができますが、これは必須ではありません。

私が見つけた唯一の解決策は各スクリプトが独自にtmp削除を実行できるようにする、これは私の要件の項目3を満たしていません。

私のような要件のベストプラクティスは何ですか?

答え1

スクリプトがそれ自体が混乱している部分をクリーンアップできない場合、これは理想的なベストプラクティスです。したがって、私が考えることができる次善策は、既知の場所に存在し、次のものを含むセマフォファイルを使用することです。各スクリプトがそのファイルを見つけるために必要なデータです。たとえば、

#!/bin/bash
if [[ -r $HOME/run/scratchfiles ]]; then
    scratchfiles="$(cat $HOME/run/scratchfiles)"
else
    scratchfiles=$(mktemp -d) && printf "%s" "$scratchfiles" > $HOME/run/scratchfiles
fi
[...]

不要になったファイルのクリーンアップを担当するスクリプトは、単に[[ -d "$scratchfiles" ]] && rm -fr "$scratchfiles"上記を提供できます。

答え2

Bashを使用している場合は、withtemp一時ファイルを処理するためにしばらく前にユーティリティ関数を作成しました。この関数はサブシェルで実行され、コマンドを実行して引数リストに一時ファイルパスを追加するか、代替文字列(たとえば)が指定されている場合はすべての一時ファイルとn番目の一時ファイルを{}置き換えます。次のオプションが定義されます。{}{n}

  • -s:ファイルを削除するときにshred代わりに使用されます。rm
  • -c <command>: それぞれを評価してcommandstdout を次の一時ファイルにリダイレクトし、追加コマンドは最後のファイルにリダイレクトされます。
  • -n <number>:作成する一時ファイルの数。
  • -r <replacement>:代替文字列を使用します。
bash-5.1$ type withtemp
withtemp is a function
withtemp () 
{ 
    ( local -a RM=(rm -f);
    local -a COMMANDS=();
    local REPSTR='';
    local REPSTRN='';
    local -i NUMFILES=1;
    local TMPFILE;
    local -a TMPFILES=();
    local -a TMPFDS=();
    local -i i;
    unset OPTIND;
    while getopts sc:n:r: OPTION; do
        case "$OPTION" in 
            s)
                RM=(shred -zu)
            ;;
            c)
                COMMANDS+=("$OPTARG")
            ;;
            n)
                NUMFILES=$OPTARG
            ;;
            r)
                REPSTR=$OPTARG
            ;;
        esac;
    done;
    [ $NUMFILES -le 0 ] && NUMFILES=1;
    for ((i = 0; i < $NUMFILES; ++i))
    do
        TMPFILE=$(mktemp);
        exec {TMPFDS[$i]}> $TMPFILE;
        TMPFILES+=($TMPFILE);
    done;
    trap '"${RM[@]}" "${TMPFILES[@]}"' EXIT;
    i=0;
    for c in "${COMMANDS[@]}";
    do
        eval "$c" 1>&${TMPFDS[$i]};
        [ $((i + 1)) -lt ${#TMPFDS[@]} ] && (( ++i ));
    done;
    for i in ${TMPFDS[@]};
    do
        exec {i}>&-;
    done;
    shift $OPTIND
    if [ -n "$REPSTR" ]; then
        set -- "${@//$REPSTR/${TMPFILES[@]}}";
        for i in "${!TMPFILES[@]}";
        do
            REPSTRN=${REPSTR:0:-1}$((i + 1))${REPSTR: -1};
            set -- "${@//$REPSTRN/${TMPFILES[$i]}}";
        done;
    else
        set -- "$@" "${TMPFILES[@]}";
    fi;
    eval "$@" )
}
bash-5.1$ withtemp -n2 -c 'echo executing first command >&2; echo temp file one contents' \
                   -c 'echo executing second command >&2; echo temp file two contents' \
                   head -v
executing first command
executing second command
==> /tmp/tmp.47hSk9mVe4 <==
temp file one contents

==> /tmp/tmp.tBWnCc2ri1 <==
temp file two contents
bash-5.1$ withtemp -s -n2 -r{} -c 'tac /etc/passwd' -c 'tac /etc/group' \
                   'grep ^root: {2} {1}'
/tmp/tmp.OwMdFfuEMw:root:x:0:root
/tmp/tmp.eTXi6Ti17n:root:x:0:0::/root:/bin/bash

関連情報