Encontrar el directorio tmp correcto en múltiples plataformas

46

Tengo un script que necesita crear archivos temporales para su trabajo, y limpiar después de sí mismo. Mi pregunta es acerca de encontrar el directorio base correcto para los archivos temporales.

El script debe funcionar en múltiples plataformas: Git Bash (Windows), Solaris, Linux, OSX. En cada plataforma, el directorio temporal preferido se expresa de manera diferente:

  • Windows: %TMP%(y posiblemente %TEMP%)
  • OSX: $TMPDIR
  • Linux, UNIX: se supone que es, $TMPDIRpero parece no estar configurado en varios sistemas que probé

Entonces, en mi script, agregué este repetitivo:

if test -d "$TMPDIR"; then
    :
elif test -d "$TMP"; then
    TMPDIR=$TMP
elif test -d /var/tmp; then
    TMPDIR=/var/tmp
else
    TMPDIR=/tmp
fi

Esto parece demasiado tedioso. ¿Hay una mejor manera?

Detener el daño continuo a Mónica
fuente
66
Solo úsalo ${TMPDIR-/tmp}en Me gusta de Unix. TMPDIRestá allí (por el sistema, el administrador o el usuario) para indicarle cuándo no usarlo /tmppara archivos temporales.
Stéphane Chazelas

Respuestas:

72

Una forma un poco más portátil de manejar archivos temporales es usar mktemp. Creará archivos temporales y devolverá sus rutas por usted. Por ejemplo:

$ mktemp
/tmp/tmp.zVNygt4o7P
$ ls /tmp/tmp.zVNygt4o7P
/tmp/tmp.zVNygt4o7P

Podrías usarlo en un script con bastante facilidad:

tmpfile=$(mktemp)
echo "Some temp. data..." > $tmpfile
rm $tmpfile

Al leer la página de manual, debería poder configurar las opciones según sus necesidades. Por ejemplo:

  • -d crea un directorio en lugar de un archivo.
  • -u genera un nombre, pero no crea nada.

Utilizando -upodría recuperar el directorio temporal con bastante facilidad con ...

$ tmpdir=$(dirname $(mktemp -u))

Más información sobre mktempestá disponible aquí .

Editar con respecto a Mac OS X: nunca he usado un sistema Mac OSX, pero según un comentario de Tyilo a continuación, parece que Mac OSX mktemprequiere que proporciones una plantilla (que es un argumento opcional en Linux). Citando:

La plantilla puede ser cualquier nombre de archivo con algún número de "X" adjuntas, por ejemplo /tmp/temp.XXXX. Las "X" finales se reemplazan con el número de proceso actual y / o una combinación de letras única. El número de nombres de archivo únicos que puede devolver mktemp depende del número de "X" proporcionadas; seis "X" darán como resultado que mktemp seleccione 1 de 56800235584 (62 ** 6) posibles nombres de archivo.

La página de manual también dice que esta implementación está inspirada en la página de manual de OpenBSD mktemp. Por lo tanto, los usuarios de OpenBSD y FreeBSD también podrían observar una divergencia similar (consulte la sección Historial ).

Ahora, como probablemente notó, esto requiere que especifique una ruta de archivo completa, incluido el directorio temporal que está buscando en su pregunta. Este pequeño problema se puede manejar con el -tinterruptor. Si bien esta opción parece requerir un argumento ( prefix), parece que se mktempbasa $TMPDIRcuando es necesario.

Con todo, debería poder obtener el mismo resultado que el anterior utilizando ...

$ tmpdir=$(dirname $(mktemp tmp.XXXXXXXXXX -ut))

Cualquier comentario de los usuarios de Mac OS X sería muy apreciado, ya que no puedo probar esta solución yo mismo.

John WH Smith
fuente
El OP abordó este problema en un comentario ahora eliminado; Me temo que no puedo proporcionar una respuesta para los sistemas que requieren gitbashobtener una interfaz de shell, de ahí mi "levemente". Realmente no podría decir dónde están almacenados los archivos temporales en un sistema Windows ...
John WH Smith
1
lo mismo. Algunos locos c:\User\Name\..............\stuff. Y probablemente hay 100 de ellos. Aún así, algunas distribuciones de Linux se están acercando al mismo nivel de locura /var. Solo tenía curiosidad. Me pareció una forma extraña de decirlo todo: en mi experiencia, la frustración es muy portátil, y la conveniencia no lo es tanto. Muy buena respuesta de todos modos.
mikeserv
1
Hace aproximadamente un año, escribí un script de Bash para manipular los archivos de punto de restauración de Windows que funciona en Win2K a través de WinXP (las versiones posteriores manejan esas cosas de manera diferente). Mi script usa WINDOWS/Tempo Windows/Tempcomo el directorio predeterminado para sus archivos temporales; ese directorio también existe en máquinas con Windows 7. Pero mi script permite al usuario proporcionar un directorio temporal alternativo en la línea de comando.
PM 2Ring
Esto no funcionaría en OS X, ya que debe proporcionar una plantilla mktemp.
Tyilo
1
Desde El Capitán, mktempsimplemente funciona: simple mktempdevuelve un archivo y mktemp -ddevuelve un directorio; No se requieren plantillas. Sin embargo, el manual no se actualiza.
Franklin Yu
9

Si está buscando lo mismo en menos líneas ...

for TMPDIR in "$TMPDIR" "$TMP" /var/tmp /tmp
do
    test -d "$TMPDIR" && break
done

Podrías escribir esto en uno.

Frostschutz
fuente
Probablemente también deberías probar si se puede escribir.
frostschutz
@janos: Y si todo lo demás falla, solicite al usuario que proporcione una ruta para los archivos temporales, o permita que especifiquen uno en la línea de comando.
PM 2Ring
6

Usted puede hacer:

: "${TMPDIR:=${TMP:-$(CDPATH=/var:/; cd -P tmp)}}"
cd -- "${TMPDIR:?NO TEMP DIRECTORY FOUND!}" || exit

El shell debe encontrar un directorio ejecutable en una de las 4 alternativas o salir con un error significativo. Aún así, POSIX define la $TMPDIRvariable (para sistemas XCU) :

TMPDIR Esta variable representará una ruta de acceso de un directorio disponible para programas que necesitan un lugar para crear archivos temporales.

También requiere el /tmpcamino.

mikeserv
fuente
1
Esta es la única respuesta correcta aquí OMI. No sé lo que está haciendo sentado en el fondo sin votos ...
Graeme
2
@Graeme: ¿tal vez porque es completamente ilegible?
ssc
Voté, pero luego lo retiré, sí, esta respuesta es un desastre, parece estar en una pista útil, pero no está del todo claro qué está tratando de hacer el fragmento de código: la primera línea es un comentario y la segunda uno es un error (en bash, de todos modos). Podría usar algo de trabajo.
Don Hatch
Ah, ya veo, la primera versión de la respuesta fue más clara (aunque sigue siendo un error en la segunda línea si realmente intentas ejecutarla) ... y luego una serie de ediciones destrozaron completamente el ejemplo de código, por lo que ahora no tiene sentido. Podría usar otro pase o dos :-)
Don Hatch