Creating Temporary Files in Bash

Creating temporary files in bash

The mktemp(1) man page explains it fairly well:

Traditionally, many shell scripts take the name of the program with
the pid as a suffix and use that as a temporary file name. This kind
of naming scheme is predictable and the race condition it creates is
easy for an attacker to win. A safer, though still inferior, approach
is to make a temporary directory using the same naming scheme. While
this does allow one to guarantee that a temporary file will not be
subverted, it still allows a simple denial of service attack. For
these reasons it is suggested that mktemp be used instead.

In a script, I invoke mktemp something like

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

which creates a temporary directory I can work in, and in which I can safely name the actual files something readable and useful.

mktemp is not standard, but it does exist on many platforms. The "X"s will generally get converted into some randomness, and more will probably be more random; however, some systems (busybox ash, for one) limit this randomness more significantly than others


By the way, safe creation of temporary files is important for more than just shell scripting. That's why python has tempfile, perl has File::Temp, ruby has Tempfile, etc…

What will be the best way to create a temporary text file for bash output processing and delete the file after the process ends

Continuing from the comment, in addition to creating the temporary file and setting a trap to remove the temp file on termination, interrupt or exit, you should validate each step along the way. You should validate mktemp provides a zero exit code. You should validate that the temp file is in fact created. Then you can use the temp file with confidence that no intervening error took place.

A short example would be:

#!/bin/bash

tmpfile=$(mktemp) ## create temporary file

[ "$?" -eq 0 ] || { ## validate zero exit code from mktemp
printf "error: mktemp had non-zero exit code.\n" >&2
exit 1
}

[ -f "$tmpfile" ] || { ## validate temp file actually created
printf "error: tempfile does not exist.\n" >&2
exit 1
}

## set trap to remove temp file on termination, interrupt or exit
trap 'rm -f "$tmpfile"' SIGTERM SIGINT EXIT

## Your Script Content Goes Here, below simply exercises the temp file as an example

## fill temp file with heredoc to test
cat > "$tmpfile" << eof
The temporary file was successfully create at: '$tmpfile'.
The temporary file will be removed by a trap function when this
script is terminated or interrupted, or when this script exits
normally.
eof

cat "$tmpfile" ## output temp file to terminal

There are several ways to approach this. This is just a plain-Jane, non-exiting way to put the pieces together and the validations to ensure it all happens as you intend.

How do you create an array of temporary files in bash?

You have a couple of syntax errors which I've marked below:

declare -A my_array
my_array=()

for i in `seq -w 1 10`
do
my_array[$i]=$(mktemp /tmp/$i.XXXX)
# ^^
# | no space
done

#Do stuff with the files in the array

for i in `seq -w 1 10`
do
rm "${my_array[$i]}"
# ^^^ ^^
# | | dollar sign and curly braces required, quotes recommended
done

Try using ShellCheck to check your scripts for errors. It has better diagnostics than the shell's built-in ones. It can be downloaded as a CLI tool, or you can just paste your script into the web site. Pretty convenient!

Some additional improvements:

  • There's no need to use declare -A when you've got a regular non-associative array.
  • for ((i = 0; i < n; i++)) avoids an unnecessary call to an external process like seq.
  • You can append to an array with array+=(items...).
  • You can often avoid explicitly looping over arrays. Many commands, rm included, take lists of file names, which you can use to your advantage. "${array[@]}" expands to all of the items in the array.
  • There's no real need to micromanage mktemp's file name generation. Letting it use the default algorithm is nice because it'll respect the user's $TMPDIR setting in case they want to use a directory other than /tmp. (If you do want to control the file name use --tmpdir to get the same behavior.)
files=()
for ((i = 1; i <= 10; i++)); do
files+=("$(mktemp)") # or: files+=("$(mktemp --tmpdir "$i".XXXX)")
done

# Do stuff with files in the array.
rm "${files[@]}"

Create temporary file and edit contents and return the path to the file

In the fish shell, you could define a function, here mt:

function mt
set -l path (mktemp)
micro $path </dev/tty >/dev/tty
cat $path
end

Now your pipelines can work with mt:

mt | wc

How to create temporary shellscript files and directories through Tcl language?

Creating temporary files can be done using file tempfile. For directories file tempdir will be available in Tcl 8.7.

On Tcl versions before 8.7, you can use file tempfile to obtain a path to a temporary location and then create a directory by that name:

set fd [file tempfile temp]
close $fd
file delete $temp
file mkdir $temp

The file tempfile command also allows you to specify a template, similar to the -p option of mktemp


To answer your updated question, you can do something like:

# Create a temporary file
set temp [exec mktemp]
# Save all content from the entered path
exec ls -l [lindex $argv 0] > $temp
# Read temporary file
set f [open $temp]
set lines [split [read $f] \n]
close $f
# List only directories
puts [join [lsearch -all -inline $lines {d*}] \n]

I ignored your mixing up of directories and regular files and whatever the *.jpg is supposed to be.

Your attempts to create shell variables from inside Tcl and then use those in the next exec command will always fail because those variables are gone when the first subshell terminates. Keep the results in Tcl variables instead, like I did above.

Of course you could more easily find the directories using glob -type d, but I kept the shell command to serve as an example.


With example, the creating of directory temporary It would be like this:

# Create a temporary directory
set dir [exec mktemp -d] ;

# Now, files insert in directory
# (In this example I am decompressing a ZIP file and only JPEG format images)
exec unzip -x $env(HOME)/file.zip *.jpg -d $dir ;

# Look the directory now with this command:
puts [glob -nocomplain -type f -directory $dir -tails *.jpg] ;

creating a temporary file in memory and using it as input file of a command

You can use process substitution for this:

pdflatex <(echo "$stuff")

From the Bash Reference Manual:

3.5.6 Process Substitution

Process substitution is supported on systems that support named pipes
(FIFOs) or the /dev/fd method of naming open files. It takes the form
of

<(list)

or

>(list)

The process list is run with its input or output connected to a FIFO or some file in /dev/fd. The name of this file is passed as an argument to the current command as the result of the expansion. If the
>(list) form is used, writing to the file will provide input for list. If the <(list) form is used, the file passed as an argument should be read to obtain the output of list. Note that no space may appear between the < or > and the left parenthesis, otherwise the construct would be interpreted as a redirection.

And I also wonder if a here-string would make it as well:

pdflatex <<< "$stuff"


Related Topics



Leave a reply



Submit