다른("응용 프로그램") 스크립트에 대한 임시 파일을 사용하여 전체 작업 집합을 처리하는 재사용 가능한("유틸리티") 스크립트를 만들어야 합니다.
- 만들다
- 생성된 임시 파일을 추적하세요.
- 이탈(정기적인 사용자 완료 및 중단)을 포착하고 생성된 모든 항목을 삭제합니다.
각 응용 프로그램 스크립트는 사용하는 모든 하위 스크립트에 대해 한 번 호출하는 일부 "기본" 스크립트에 의존하는 대신 유틸리티 스크립트 자체를 "포함"해야 합니다.
핵심 요구 사항은 유틸리티 스크립트를 사용하는 응용 프로그램 스크립트가 서로 호출할 수 있어야 하며 각 스크립트는 차례로 임시 파일을 사용해야 한다는 것입니다. 스크립트 간의 모든 호출은
./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>
: 각각을 평가하여command
stdout을 다음 임시 파일로 리디렉션하고 추가 명령은 마지막 파일로 리디렉션됩니다.-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