Solución o alternativa para mktemp en OS X

73

Estoy viendo un script bash que alguien más escribió que usa mktemp:

TEMP=`mktemp --directory`

Sin embargo, esta línea no funciona en mi máquina (OS X 10.6).

¿Cómo arreglaría esta línea para que sea compatible con cross-un * x-like-platform? EDITAR: un comando alternativo también sería suficiente.

Mindeavor.
fuente

Respuestas:

109

Lo siguiente es lo que terminé usando para crear de manera confiable un directorio temporal que funciona tanto en Linux como en Darwin (todas las versiones anteriores a Mac OS X 10.11), sin codificación $TMPDIRo /tmp:

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

Antecedentes:

El comando GNU mktemp no requiere argumentos. Plain mktempfuncionará y creará un archivo temporal en el directorio temporal del sistema.

Plain mktemp -dcreará un directorio en lugar de un archivo, que es lo que querría usar en Linux.

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

Por defecto, GNU mktemp usa la plantilla tmp.XXXXXXXXXXpara el nombre del subdirectorio (o archivo). Para personalizar esta plantilla, -tse puede usar la opción.

Mktemp de OSX no tiene una plantilla predeterminada y requiere que se especifique una plantilla. Desafortunadamente, donde GNU mktemp toma la plantilla como -topción, en OSX esto se pasa como argumento posicional. En cambio, mktemp de OSX tiene una -topción que significa otra cosa. La -topción en OSX está documentada como un "prefijo" para la plantilla. Se expande a {prefix}.XXXXXXXX, por lo que agrega las X automáticamente (por ejemplo, mktemp -d -t examplepodría crear example.zEJZWCTQen el directorio temporal).

Me sorprendió descubrir que en muchos entornos Linux, no$TMPDIR está configurado por defecto. Muchos programas CLI lo admiten cuando se configura, pero aún necesitan un valor predeterminado para . Esto significa que pasar a mktemp o mkdir es peligroso porque puede producirse en el directorio raíz del disco local (debido a que $ TMPDIR se desarma y se convierte en una cadena vacía)./tmp$TMPDIR/example.XXXXXXXX/example.XXXXXXXX

En OSX, $TMPDIRsiempre se establece y (al menos en el shell predeterminado) no se establece en /tmp(que es un enlace simbólico /private/tmp) sino en /var/folders/dx/*****_*************/T. Entonces, hagamos lo que hagamos para OSX, debería honrar ese comportamiento predeterminado.

En conclusión, lo siguiente es lo que terminé usando para crear de manera fiable un directorio temporal que funciona tanto en Linux y Darwin (Mac OS X), sin codificar, ya sea $TMPDIRo /tmp:

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

La primera parte es para Linux. Este comando fallará en Darwin (Mac OS X) con un código de estado de error que 1responde con "uso: ...". Es por eso que ignoramos stderr y en su lugar ejecutamos la variante Mac. El mytmpdirprefijo solo se usa en Mac (donde se requiere establecer esa opción).

Timo Tijhof
fuente
12
Realmente genial. A veces, el comportamiento diferente de OS X es molesto.
therealmarv
66
@therealmarv Prefiero decir, siempre.
Nikita Volkov
10
Acabo de ejecutar mktemp -den OS X 10.11.5 El Capitan, y funcionó como se esperaba file $(mktemp -d): /var/folders/j4/htlnmbf97vlcdszj7_x8g0vh4k3_fp/T/tmp.JXmsrQnL: directory
Heath Borders
2
Sí. Me sorprendió como tú que este Just Worked ™.
Heath Borders
1
Además, si ejecuta mktemp -d -t 'mytmpdir'Linux (probado con mktempfrom coreutils 8.26), funciona como se esperaba.
15

Tienes que proporcionar una plantilla. mktemp -d /tmp/foo.XXXXDeberia trabajar. Nunca he visto --directory. El --sugiere que es una extensión GNU.

Kyle Jones
fuente
66
Si desea usar $TMPDIRcuando esté disponible, hágalo mktemp -d "${TMPDIR:-/tmp}"/foo.XXXX. Eso funciona en bash en Mac y en Debian, por lo que parece portátil.
Tom Anderson
9

Cambiar --directorya -d. El primero es un GNU-ismo, pero GNU mktempde coreutils también es compatible -d. El mktempOS X es el mismo que el de BSD, por lo que -ddebería ser bastante portátil entre los sistemas que realmente envían un mktempprograma.

James Sneeringer
fuente
Acabo de intentarlo mktemp -d, y tampoco funciona.
Mindeavor.
1
Kyle tiene la respuesta completa. El mktempen OS X requiere una plantilla. El script que está utilizando asume las convenciones de GNU, que usa una plantilla predeterminada si no se proporciona ninguna.
James Sneeringer el
El problema es que Unix espera XXXXXque se suministre en la plantilla, ya que OS X no está seguro de si hay una bandera de plantilla compatible.
user3467349
2
mktempen OS X 10.11.5 El Capitan funciona para mí 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")"
  • mktemppara BSD (incluido OSX ) requiere una plantilla, pero permite cualquier número de Xs en la plantilla.
  • (GNU) mktemppara Linux no requiere una plantilla, sin embargo, si se especifica una plantilla, el número de Xs debe ser 6.

Tenga en cuenta que -testá en desuso para GNUmktemp , por lo que un código más a prueba de futuro sería

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