Como criar um arquivo temporário no shell script?

130

Ao executar um script, desejo criar um arquivo temporário no diretório /tmp .

Após a execução desse script, isso será limpo por esse script.

Como fazer isso no script de shell?

    
por Bhuvanesh 30.01.2015 / 08:02

5 respostas

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

Você pode garantir que um arquivo seja excluído quando os scripts saírem (incluindo abates e travamentos) abrindo um descritor de arquivo para o arquivo e excluindo-o. O arquivo fica disponível (para o script; não para outros processos, mas /proc/$PID/fd/$FD é uma solução alternativa), desde que o descritor de arquivo esteja aberto. Quando ele é fechado (o que o kernel faz automaticamente quando o processo é encerrado), o sistema de arquivos exclui o arquivo.

tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
exec 3>"$tmpfile"
rm "$tmpfile"
: ...
echo foo >&3
    
por 30.01.2015 / 08:07
51

Use mktemp para criar um arquivo ou diretório temporário:

temp_file=$(mktemp)

Ou para um direcotry:

temp_dir=$(mktemp -d)

No final do script, você precisa excluir o arquivo / diretório temporário:

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

mktemp cria o arquivo no diretório /tmp ou na drectory dada com o argumento --tmpdir .

    
por 30.01.2015 / 08:07
13

Se você está no sistema que tem mktemp , você deve usá-lo como outras respostas.

Com o toolchest POSIX:

umask 0177
tmpfile=/tmp/"$0"."$$"."$(awk 'BEGIN {srand();printf "%d\n", rand() * 10^10}')"
trap 'rm -f -- "$tmpfile"' INT TERM HUP EXIT
: > "$tmpfile"
    
por 30.01.2015 / 08:32
10

Algumas camadas têm o recurso embutido.

zsh

A forma de zsh de substituição de processo de =(...) de processo usa um arquivo temporário. Por exemplo, =(echo test) expande para o caminho de um arquivo temporário que contém 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

Esse arquivo é removido automaticamente assim que o comando terminar.

bash / zsh no Linux.

Aqui, os arquivos ou as sequências aqui em bash e zsh são implementados como arquivos temporários excluídos.

Então, se você fizer isso:

exec 3<<< test

O descritor de arquivo 3 está conectado a um arquivo temporário excluído que contém test\n .

Você pode obter seu conteúdo com:

cat <&3

Se no Linux, você também pode ler ou gravar no arquivo via /dev/fd/3

$ exec 3<<< test
$ cat <&3
test
$ echo foo > /dev/fd/3
$ cat /dev/fd/3
foo

(alguns outros shells usam pipes, ou podem usar /dev/null se o doc aqui estiver vazio).

POSIX

Não existe o utilitário mktemp POSIX. No entanto, o POSIX especifica uma mkstemp(template) C API e o utilitário m4 standard expõe essa API com a função mkstemp() m4 com o mesmo nome.

mkstemp() fornece um nome de arquivo com uma parte aleatória que era garantida a não existir no momento em que a função foi chamada. Ele cria o arquivo com permissões 0600 de uma maneira livre de raça.

Então, você poderia fazer:

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

Note, entretanto, que você precisa lidar com a limpeza ao sair, mas se você só precisa escrever e ler o arquivo um número fixo de vezes, você pode abri-lo e deletá-lo logo após criar um arquivo para o aqui-doc Abordagem here-string acima:

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

Você poderia abrir o arquivo para leitura uma vez e retroceder entre duas leituras, como não há nenhum utilitário POSIX que possa retroceder ( lseek() ), portanto, não é possível portá-lo em um script POSIX ( zsh ( sysseek builtin) e ksh93 ( <#((...)) operator) podem fazê-lo embora.

    
por 30.01.2015 / 13:17
5

Aqui está uma resposta um pouco melhor na linha 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
    
por 09.05.2017 / 14:34