Correction ou alternative pour mktemp sous OS X

73

Je regarde un script bash écrit par quelqu'un d'autre qui utilise mktemp:

TEMP=`mktemp --directory`

Cependant, cette ligne ne fonctionne pas sur ma machine (OS X 10.6).

Comment pourrais-je réparer cette ligne afin qu'elle soit compatible avec plusieurs plates-formes x? EDIT: Une commande alternative serait également suffisante.

mentalité
la source

Réponses:

109

Voici ce que j’ai utilisé pour créer de manière fiable un répertoire temporaire fonctionnant à la fois sous Linux et Darwin (toutes les versions antérieures à Mac OS X 10.11), sans codage en dur $TMPDIRni /tmp:

mytmpdir=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'`

Contexte:

La commande GNU mktemp ne nécessite aucun argument. Plain mktempfonctionnera et créera un fichier temporaire dans le répertoire temporaire du système.

Plain mktemp -dva créer un répertoire à la place d'un fichier, ce que vous voudriez utiliser sous Linux.

(gnu-coreutils)$ man mktemp
> ..
> If DIR is not specified, uses $TMPDIR if set, else /tmp.
> ..

Par défaut, GNU mktemp utilise le modèle tmp.XXXXXXXXXXpour le nom du sous-répertoire (ou fichier). Pour personnaliser ce modèle, l' -toption peut être utilisée.

La mktemp d'OSX n'a ​​pas de modèle par défaut et nécessite la spécification d'un modèle. Malheureusement, lorsque GNU mktemp prend le modèle en -toption, sous OSX, il est passé en argument de position. Au lieu de cela, mktemp d'OSX a une -toption qui signifie autre chose. L' -toption sur OSX est documentée en tant que "préfixe" pour le modèle. Il est développé de {prefix}.XXXXXXXXmanière à y ajouter les X automatiquement (par exemple, mktemp -d -t examplecréer example.zEJZWCTQdans le répertoire temporaire).

J'ai été surpris de constater que dans de nombreux environnements Linux, ce $TMPDIRn'est pas défini par défaut. De nombreux programmes CLI le prennent en charge une fois défini, mais nécessitent toujours une valeur par défaut pour /tmp. Cela signifie que passer $TMPDIR/example.XXXXXXXXà mktemp ou mkdir est dangereux car cela peut produire /example.XXXXXXXXdans le répertoire racine du disque local (car $ TMPDIR est non défini et devient une chaîne vide).

Sur OSX, $TMPDIRest toujours défini et (du moins dans le shell par défaut), il est défini non sur /tmp(ce qui est un lien symbolique /private/tmp), mais sur /var/folders/dx/*****_*************/T. Donc, quoi que nous fassions pour OSX, nous devrions respecter ce comportement par défaut.

En conclusion, voici ce que je fini par utiliser pour créer de manière fiable un répertoire temporaire qui fonctionne aussi bien sur Linux et Darwin (Mac OS X), sans hardcoding soit $TMPDIRou /tmp:

mytmpdir=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'`

La première partie est pour Linux. Cette commande échouera sur Darwin (Mac OS X) et le code d’état de l’erreur 1répond par "usage: ...". C'est pourquoi nous ignorons stderr et exécutons à la place la variante Mac. Le mytmpdirpréfixe n'est utilisé que sur Mac (où cette option doit être définie).

Timo Tijhof
la source
12
Vraiment cool. Parfois, le comportement différent d'OS X est agaçant.
therealmarv
6
@therealmarv je dirais plutôt, toujours.
Nikita Volkov
10
Je viens d’ mktemp -dexécuter sur OS X 10.11.5 El Capitan, et cela a fonctionné comme prévu file $(mktemp -d):: /var/folders/j4/htlnmbf97vlcdszj7_x8g0vh4k3_fp/T/tmp.JXmsrQnL: directory
Heath Borders le
2
Oui. J'ai été surpris que vous soyez que cela fonctionne Just Worked ™.
Frontières
1
De plus, si vous utilisez mktemp -d -t 'mytmpdir'Linux (testé avec mktempfrom coreutils 8.26), cela fonctionne comme prévu.
15

Vous devez fournir un modèle. mktemp -d /tmp/foo.XXXXdevrait marcher. Je n'ai jamais vu --directory. Le --suggère qu'il s'agit d'une extension GNU.

Kyle Jones
la source
6
Si vous voulez utiliser $TMPDIRquand disponible, faites mktemp -d "${TMPDIR:-/tmp}"/foo.XXXX. Cela fonctionne bash sur Mac et dash sous Debian, donc cela semble portable.
Tom Anderson
9

Changer --directoryen -d. Le premier est un GNU-isme, mais GNU mktempde coreutils le supporte également -d. Le mktempsystème d'exploitation sous OS X est identique à celui de BSD, il -ddevrait donc être assez portable parmi les systèmes qui livrent un mktempprogramme.

James Sneeringer
la source
J'ai juste essayé mktemp -d, et ça ne marche pas non plus.
mentalité.
1
Kyle a la réponse complète. Le mktempsur OS X nécessite un modèle. Le script que vous utilisez suppose les conventions GNU, qui utilisent un modèle par défaut si aucun n'est fourni.
James Sneeringer
Le problème est qu’unix s'attend XXXXXà être fourni dans le modèle alors qu’OS X ne sait pas s’il existe un indicateur de modèle compatible.
user3467349
2
mktempsur El Capitan fonctionne pour OS X 10.11.5 file $(mktemp -d)::/var/folders/j4/htlnmbf97vlcdszj7_x8g0vh4k3_fp/T/tmp.JXmsrQnL: directory
Heath Borders
4
temp_dir="$(mktemp -q -d -t "$(basename "$0").XXXXXX")"
  • mktemppour BSD (y compris OSX ) nécessite un modèle, mais il permet un nombre quelconque de Xs dans le modèle.
  • (GNU) mktemppour Linux ne nécessite pas de modèle. Toutefois, si un modèle est spécifié, le nombre de Xs doit être 6.

Notez que cette méthode -test obsolète pour GNUmktemp . Par conséquent, un code plus évolutif serait

temp_dir="$(mktemp -q -d -t "$(basename "$0").XXXXXX" 2>/dev/null || mktemp -q -d)"
go2null
la source