シェルスクリプトで一時ファイルを作成するには?

シェルスクリプトで一時ファイルを作成するには?

/tmpスクリプトを実行するときにディレクトリに一時ファイルを作成したいと思います。

スクリプトを実行すると、スクリプトはスクリプトを消去します。

シェルスクリプトでこれを行うにはどうすればよいですか?

答え1

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

ファイル記述子を開いて削除すると、スクリプトの終了時に(終了と競合を含む)ファイルを削除することができます。/proc/$PID/fd/$FDファイル記述子が開いている限り、ファイルは引き続き使用可能です(スクリプトの場合、実際には他のプロセスではありませんが解決策)。ファイルが閉じられると(プロセスが終了するとカーネルは自動的にこれを実行します)、ファイルシステムはファイルを削除します。

# create temporary file
tmpfile=$(mktemp /tmp/abc-script.XXXXXX)

# create file descriptor 3 for writing to a temporary file so that
# echo ... >&3 writes to that file
exec 3>"$tmpfile"

# create file descriptor 4 for reading from the same file so that
# the file seek positions for reading and writing can be different
exec 4<"$tmpfile"

# delete temp file; the directory entry is deleted at once; the reference counter
# of the inode is decremented only after the file descriptor has been closed.
# The file content blocks are deallocated (this is the real deletion) when the
# reference counter drops to zero.
rm "$tmpfile"

# your script continues
: ...

# example of writing to file descriptor
echo foo >&3

# your script continues
: ...

# reading from that file descriptor
head -n 1 <&4

# close the file descriptor (done automatically when script exits)
# see section 2.7.6 of the POSIX definition of the Shell Command Language
exec 3>&-

答え2

mktemp一時ファイルの作成に使用されます。このユーティリティは、生成されたファイルのフルパスを返します。

temp_file=$(mktemp)

または一時生成目次:

temp_dir=$(mktemp -d)

スクリプトが終了したら、一時ファイルまたはディレクトリを削除できます。

rm "${temp_file}"
rm -r "${temp_dir}"

注:引数で指定されたディレクトリにmktempファイルを作成します。追加のオプションと動作を変更する方法については、ユーティリティのマニュアルを参照してください。/tmp--tmpdir

答え3

一部のシェルには組み込み機能があります。

扱いにくい

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。

Here-documentsまたはhere-stringsは、bash5.1より前のバージョンでzsh削除された一時ファイルとして実装されました(1970年代後半にhere-documentが導入されたときにBourneシェルの場合のように)。

その場合は、次のようにしてください。

exec 3<<< test

ファイル記述子3は、削除された一時ファイルを含むファイルにリンクされていますtest\n

以下からコンテンツを入手できます。

cat <&3

Linuxではファイルを読み書きできますが、/dev/fd/3bashバージョン5.0では最初にファイルへの書き込み権限を復元する必要があります(bashはそのバージョンから明示的に削除しました)。

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

(一部の他のシェルはパイプを使用するか、/dev/nullここで文書が空の場合は使用できます)。

POSIX

POSIXユーティリティはありませんmktemp。しかし、POSIXはmkstemp(template)アプリケーションプログラミングインターフェース標準ユーティリティは、m4同じ名前のm4関数を使用してこのAPIを公開します。mkstemp()

mkstemp()関数が呼び出されたときに存在しないことを保証する任意の部分を含むファイル名を提供します。競合のない方法で権限0600を使用してファイルを生成します。

したがって、次のようにすることができます。

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

ただし、終了時にクリーンアップ操作を処理する必要がありますが、ファイルを指定された回数だけ書き込んで読み取る必要がある場合は、上記のhere-doc / here-charのように文字列メソッドを作成してから開いて削除できます。 :

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回の読み取りのためにファイルを開いてから読み取り間で巻き戻すことができますが、rewind()操作を実行するPOSIXユーティリティがないため、POSIXスクリプト((組み込み)および(演算子)lseek()では簡単に実行できません。 。zshsysseekksh93<#((...))

答え4

以下は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

関連情報