Créer des fichiers temporaires dans bash

150

Existe-t-il des moyens objectivement meilleurs de créer des fichiers temporaires dans des scripts bash?

Normalement, je les nomme simplement ce qui me vient à l'esprit, comme tempfile-123, car il sera supprimé lorsque le script sera terminé. Y a-t-il un inconvénient à faire cela autre que l'écrasement d'un éventuel fichier tempfile-123 dans le dossier actuel? Ou y a-t-il un avantage à créer un fichier temporaire de manière plus prudente?

Strapakowsky
la source
1
N'utilisez pas de fichiers temporellement. Utilisez plutôt des répertoires temporels. Et n'utilisez pas mktemp. Voir ici pourquoi: codeproject.com/Articles/15956/...
ceving
17
@ceving Cet article est tout simplement faux, du moins lorsqu'il est appliqué à la commande shell mktemp (par opposition à l'appel de la bibliothèque mktemp). Comme mktemp crée le fichier lui-même avec un umask restrictif, l'attaque donnée ne fonctionne que si l'attaquant opère sous le même compte que l'attaquant ... auquel cas le jeu est déjà perdu. Pour les meilleures pratiques dans le monde des scripts shell, voir mywiki.wooledge.org/BashFAQ/062
Charles Duffy
Vous pouvez également utiliser tempfile(1)sur les systèmes qui en ont.
Suspendu jusqu'à nouvel ordre.

Réponses:

179

La mktemp(1)page de manuel l'explique assez bien:

Traditionnellement, de nombreux scripts shell prennent le nom du programme avec le pid comme suffixe et l'utilisent comme nom de fichier temporaire. Ce type de schéma de dénomination est prévisible et la condition de concurrence qu'il crée est facile à gagner pour un attaquant. Une approche plus sûre, mais toujours inférieure, consiste à créer un répertoire temporaire en utilisant le même schéma de dénomination. Bien que cela permette de garantir qu'un fichier temporaire ne sera pas détourné, cela permet tout de même une simple attaque par déni de service. Pour ces raisons, il est suggéré d'utiliser mktemp à la place.

Dans un script, j'invoque mktemp quelque chose comme

mydir=$(mktemp -d "${TMPDIR:-/tmp/}$(basename $0).XXXXXXXXXXXX")

qui crée un répertoire temporaire dans lequel je peux travailler et dans lequel je peux nommer en toute sécurité les fichiers réels comme étant lisibles et utiles.

mktempn'est pas standard, mais il existe sur de nombreuses plates-formes. Les "X" seront généralement convertis en un certain caractère aléatoire, et plus seront probablement plus aléatoires; cependant, certains systèmes (busybox ash, pour un) limitent ce caractère aléatoire plus significativement que d'autres


À propos, la création en toute sécurité de fichiers temporaires est importante pour plus que la simple création de scripts shell. C'est pourquoi python a tempfile , perl a File :: Temp , ruby ​​a Tempfile , etc.

Kojiro
la source
1
L'option -t est obsolète: gnu.org/software/coreutils/manual/html_node/…
Tibor Vass
7
Il semble que la manière la plus sûre et la plus multiplateforme d'utiliser mktempsoit combinée avec basename, comme ça mktemp -dt "$(basename $0). XXXXXXXXXX". S'il est utilisé sans, basenamevous risquez d'obtenir une erreur comme celle-ci mktemp: modèle non valide, `/tmp/MOB-SAN-JOB1-183-ScriptBuildTask-7300464891856663368.sh.XXXXXXXXXX ', contient un séparateur de répertoire .
i4niac
7
Ignorez-les (espace supplémentaire). mktemp -dt "$(basename $0).XXXXXXXXXX"est la bonne manière.
i4niac
3
@ i4niac: il faut citer ça $0, il y a beaucoup d'espaces au pays d'OS X.mktemp -dt "$(basename "$0").XXXXXX"
Orwellophile
11
Il peut également être intéressant de supprimer le tempdir à la fin de l'exécution du script:trap "rm -rf $mydir" EXIT
KumZ
43

Oui, utilisez mktemp .

Il créera un fichier temporaire dans un dossier conçu pour stocker des fichiers temporaires et vous garantira un nom unique. Il renvoie le nom de ce fichier:

> mktemp
/tmp/tmp.xx4mM3ePQY
>
Paul
la source
19

Vous voudrez peut-être regarder mktemp

L'utilitaire mktemp prend le modèle de nom de fichier donné et en écrase une partie pour créer un nom de fichier unique. Le modèle peut être n'importe quel nom de fichier avec un certain nombre de «X» ajouté, par exemple /tmp/tfile.XXXXXXXXXX. Les «X» de fin sont remplacés par une combinaison du numéro de processus actuel et de lettres aléatoires.

Pour plus de détails: man mktemp

John Lawrence
la source
11

Y a-t-il un avantage à créer un fichier temporaire de manière plus prudente

Les fichiers temporaires sont généralement créés dans le répertoire temporaire (tel que /tmp) où tous les autres utilisateurs et processus ont un accès en lecture et en écriture (tout autre script peut y créer les nouveaux fichiers). Par conséquent, le script doit faire attention à la création des fichiers, par exemple en utilisant les bonnes autorisations (par exemple en lecture seule pour le propriétaire, voir help umask:) et le nom de fichier ne doit pas être facilement deviné (idéalement aléatoire). Sinon, si les noms de fichiers ne sont pas uniques, cela peut créer un conflit avec le même script exécuté plusieurs fois (par exemple , condition de concurrence) ou un attaquant pourrait soit détourner certaines informations sensibles (par exemple, lorsque les autorisations sont trop ouvertes et que le nom de fichier est facile à deviner) ou créer / remplacer le fichier avec leur propre version du code (comme le remplacement des commandes ou des requêtes SQL en fonction de ce qui est stocké).


Vous pouvez utiliser l'approche suivante pour créer le répertoire temporaire:

TMPDIR=".${0##*/}-$$" && mkdir -v "$TMPDIR"

ou fichier temporaire:

TMPFILE=".${0##*/}-$$" && touch "$TMPFILE"

Cependant, il est toujours prévisible et non considéré comme sûr.

Selon man mktemp, nous pouvons lire:

Traditionnellement, de nombreux scripts shell prennent le nom du programme avec le pid comme suffixe et l'utilisent comme nom de fichier temporaire. Ce type de schéma de dénomination est prévisible et la condition de concurrence qu'il crée est facile à gagner pour un attaquant.

Donc, pour être sûr, il est recommandé d'utiliser la mktempcommande pour créer un fichier ou un répertoire temporaire unique ( -d).

Kenorb
la source
2
pas exactement ce qui a été demandé. Pourtant, cela peut être une solution parfaite.
jpbochi
1
@jpbochi J'ai amélioré la réponse pour répondre à la question. Faites-moi savoir si cela vous a été utile.
kenorb
2
Cela améliore effectivement la réponse. Mon vote positif était déjà le vôtre, cependant. Je ne peux plus voter. Une suggestion que j'ai est d'expliquer ce que${0##*/} et de $$développer ou de créer un lien vers une documentation à ce sujet.
jpbochi
0

mktemp est probablement le plus polyvalent, surtout si vous prévoyez de travailler avec le fichier pendant un certain temps.

Vous pouvez également utiliser un opérateur de substitution de processus <() si vous n'avez besoin que temporairement du fichier comme entrée d'une autre commande, par exemple:

$ diff <(echo hello world) <(echo foo bar)
Barry Jones
la source