web-dev-qa-db-ja.com

シェルスクリプトで一時ファイルを作成するにはどうすればよいですか?

スクリプトの実行中に、/tmpディレクトリに一時ファイルを作成します。

そのスクリプトの実行後、それはそのスクリプトによって消去されます。

シェルスクリプトでそれを行う方法

178
Bhuvanesh
tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
: ...
rm "$tmpfile"

ファイルのファイル記述子を開いて削除することにより、スクリプトが終了したときに(強制終了やクラッシュを含む)ファイルが削除されたことを確認できます。ファイルは引き続き使用可能です(スクリプト用。実際には他のプロセス用ではなく/proc/$PID/fd/$FDは、ファイル記述子が開いている限り、回避策です。ファイルシステムが閉じられると(プロセスの終了時にカーネルが自動的に行います)、ファイルシステムはファイルを削除します。

tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
exec 3>"$tmpfile"
rm "$tmpfile"
: ...
echo foo >&3
223
Hauke Laging

mktempを使用して一時ファイルを作成します

temp_file=$(mktemp)

または、一時的なディレクトリを作成するには:

temp_dir=$(mktemp -d)

スクリプトの最後で、一時ファイルまたは一時ディレクトリを削除する必要があります

rm ${temp_file}
rm -R ${temp_dir}

mktempは、/tmpディレクトリまたは--tmpdir引数で指定されたディレクトリにファイルを作成します。

70
chaos

mktemp があるシステムを使用している場合は、それを他の回答として使用する必要があります。

POSIXツールチェストの場合:

umask 0177
tmpfile=/tmp/"$0"."$$"."$(awk 'BEGIN {srand();printf "%d\n", Rand() * 10^10}')"
trap 'rm -f -- "$tmpfile"' INT TERM HUP EXIT
: > "$tmpfile"
16
cuonglm

一部のシェルには機能が組み込まれています。

zsh

zsh=(...)形式のプロセス置換は、一時ファイルを使用します。たとえば、=(echo test)は、_test\n_を含む一時ファイルのパスに展開されます。

_$ {cat $file; ls -l /dev/fd/3; echo test2 >&3; cat $file} 3<> ${file::==(echo test)}
test
lrwx------ 1 stephane stephane 64 Jan 30 11:19 /dev/fd/3 -> /tmp/zshMLbER0
test2
_

コマンドが完了すると、そのファイルは自動的に削除されます。

linuxのbash/zsh。

bashおよびzshのhere-filesまたはhere-stringsは、削除された一時ファイルとして実装されます。

だからあなたがするなら:

_exec 3<<< test
_

ファイル記述子3は、_test\n_を含む削除済み一時ファイルに接続されています。

次の方法でコンテンツを取得できます。

_cat <&3
_

Linuxの場合、_/dev/fd/3_を介してそのファイルを読み書きすることもできますが、bashバージョン5以降では、まず書き込み権限を復元する必要があります(bashは明示的に削除します)。

_$ exec 3<<< test
$ cat <&3
test
$ chmod u+w /dev/fd/3 # only needed in bash 5+
$ echo foo > /dev/fd/3
$ cat /dev/fd/3
foo
_

(他の一部のシェルはパイプを使用しますが、ヒアドキュメントが空の場合は_/dev/null_を使用する場合があります)。

POSIX

mktemp POSIXユーティリティはありません。ただし、POSIXは mkstemp(template) C API を指定し、_m4_標準ユーティリティは同じ名前のmkstemp() m4関数でそのAPIを公開します。

mkstemp()は、関数が呼び出されたときに存在しないことが保証されたランダムな部分を含むファイル名を提供します。レースなしでパーミッション0600のファイルを作成します。

だから、あなたは行うことができます:

_tmpfile=$(
  echo 'mkstemp(template)' |
    m4 -D template="${TMPDIR:-/tmp}/baseXXXXXX"
) || exit
_

ただし、終了時にクリーンアップを処理する必要があることに注意してください。ただし、ファイルの書き込みと読み取りを一定回数行うだけの場合は、here-doc/here-のように作成した直後にファイルを開いて削除できます。上記の文字列アプローチ:

_tmpfile=$(
  echo 'mkstemp(template)' |
    m4 -D template="${TMPDIR:-/tmp}/baseXXXXXX"
) || exit

# open once for writing, twice for reading:
exec 3> "$tempfile" 4< "$tempfile" 5< "$tempfile"

rm -f -- "$tmpfile"

cmd >&3   # store something in the temp file
exec 3>&- # fd no longer needed

# read the content twice:
cat <&4
cat <&5
_

ファイルを1回読み取り用に開き、2回の読み取りの間に巻き戻すことができますが、その巻き戻しを行うことができるPOSIXユーティリティ(lseek())がないため、POSIXスクリプトで移植することはできません(zshsysseek組み込み)と_ksh93_(<#((...))演算子)でも実行できます)。

15

これは、Hauke Lagingのラインで少し改善された回答です。

#!/bin/bash

tmpfile=$(mktemp)  # Create a temporal file in the default temporal folder of the system

# Lets do some magic for the tmpfile to be removed when this script ends, even if it crashes
exec {FD_W}>"$tmpfile"  # Create file descriptor for writing, using first number available
exec {FD_R}<"$tmpfile"  # Create file descriptor for reading, using first number available
rm "$tmpfile"  # Delete the file, but file descriptors keep available for this script

# Now it is possible to work with the temporal file
echo foo >&$FD_W
echo bar >&$FD_W  # Note that file descriptor always concatenates, not overwrites

cat <&$FD_R
7
SwanS

通常、一時ファイルを使用するワークフローは、テストしているbashスクリプトが原因です。私はそれをtee上げて、それが機能していることを確認し、プロセスの次の反復のために出力を保存したいと思っています。 tmpというファイルを作成しました

#!/bin/bash
echo $(mktemp /tmp/$(date +"%Y-%m-%d_%T_XXXXXX"))

私はそれを次のように使用できるように

$ some_command --with --lots --of --stuff | tee $(tmp)

ランダムな値の前にフォーマットされた日時が好きな理由は、簡単に作成したtmpファイルを見つけることができるためです。次回は何に名前を付けるかについて考える必要がありません(そして、ダンスクリプトを取得することに集中する必要はありません)。動作するように)。

0
Frank Bryce