web-dev-qa-db-fra.com

Comment créer un fichier temporaire dans un script Shell?

Lors de l'exécution d'un script, je souhaite créer un fichier temporaire dans /tmp répertoire.

Après l'exécution de ce script, celui-ci sera nettoyé par ce script.

Comment faire cela dans le script Shell?

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

Vous pouvez vous assurer qu'un fichier est supprimé à la fermeture des scripts (y compris les éliminations et les plantages) en ouvrant un descripteur de fichier et en le supprimant. Le fichier reste disponible (pour le script; pas vraiment pour les autres processus mais /proc/$PID/fd/$FD est une solution de contournement) tant que le descripteur de fichier est ouvert. Lorsqu'il est fermé (ce que le noyau fait automatiquement à la fin du processus), le système de fichiers supprime le fichier.

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

Utilisez mktemp pour créer un fichier temporaire

temp_file=$(mktemp)

ou, pour créer un temporaire répertoire:

temp_dir=$(mktemp -d)

À la fin du script, vous devez supprimer le fichier ou répertoire temporaire

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

mktemp crée un fichier dans le /tmp ou dans le répertoire donné avec le --tmpdir argument.

70
chaos

Si vous utilisez un système qui a mktemp , vous devez l'utiliser comme autres réponses.

Avec POSIX toolchest:

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

Certains obus ont la fonctionnalité intégrée.

zsh

La forme de substitution de processus de zsh=(...) utilise un fichier temporaire. Par exemple, =(echo test) se développe sur le chemin d'un fichier temporaire qui contient 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

Ce fichier est automatiquement supprimé une fois la commande terminée.

bash/zsh sous Linux.

Les fichiers ici ou les chaînes ici dans bash et zsh sont implémentés en tant que fichiers temporaires supprimés.

Donc si vous le faites:

exec 3<<< test

Le descripteur de fichier 3 est connecté à un fichier temporaire supprimé qui contient test\n.

Vous pouvez obtenir son contenu avec:

cat <&3

Si sous Linux, vous pouvez également lire ou écrire dans ce fichier via /dev/fd/3, Mais avec bash version 5 et supérieure, vous devez d'abord lui restaurer les autorisations d'écriture (que bash supprime désormais explicitement):

$ 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

(certains autres shells utilisent des pipes, ou peuvent utiliser /dev/null si le document ici est vide).

POSIX

Il n'y a pas d'utilitaire POSIX mktemp. POSIX spécifie cependant une API mkstemp(template) C , et l'utilitaire standard m4 Expose cette API avec la fonction mkstemp() m4 du même nom.

mkstemp() vous donne un nom de fichier avec une partie aléatoire qui était garantie de ne pas exister au moment de l'appel de la fonction. Il crée le fichier avec les autorisations 0600 sans course.

Donc, vous pourriez faire:

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

Notez cependant que vous devez gérer le nettoyage à la sortie, mais si vous n'avez besoin d'écrire et de lire le fichier qu'un nombre fixe de fois, vous pouvez l'ouvrir et le supprimer juste après avoir créé comme ici-doc/ici- approche par chaîne ci-dessus:

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

Vous pouvez ouvrir le fichier en lecture une seule fois et rembobiner entre deux lectures, mais aucun utilitaire POSIX ne peut effectuer ce rembobinage (lseek()), vous ne pouvez donc pas le faire de manière portable dans un script POSIX (zsh (sysseek builtin) et ksh93 (<#((...)) operator) peut le faire).

15
Stéphane Chazelas

Voici une réponse un peu améliorée dans la lignée de 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

Mon flux de travail généralement avec des fichiers temporaires est dû à un script bash que je teste. Je veux tee pour que je puisse voir que cela fonctionne et enregistrer la sortie pour la prochaine itération de mon processus. J'ai créé un fichier appelé tmp

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

afin que je puisse l'utiliser comme

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

La raison pour laquelle j'aime le format datetime avant les valeurs aléatoires est qu'il me permet de trouver facilement le fichier tmp que je viens de créer, et je n'ai pas à penser à quoi le nommer la prochaine fois (et me concentrer uniquement sur l'obtention de mon script dang travailler).

0
Frank Bryce