I've seen several answers on SO about how to append to a file if it exists and create a new file if it doesn't (echo "hello" >> file.txt
) or overwrite a file if it exists and create one if it doesn't (echo "hello" > file.txt
).
But how do I make sure that echo "hello"
only works and appends to the file if it already exists and raises an error if it doesn't?
EDIT: Right now, I'm already checking for the file using [ -f file.txt ]
. I was wondering if there's a way in which I could simply use echo
.
Create file if it does not exist by Using append mode If the file does not exist, it creates a new file for reading and writing. It will not truncate the file and append the content at end of the file as shown in the example below.
Open file in append mode. If file does not exist, it creates a new file. This is the default mode.
Conclusion. In Linux, to append text to a file, use the >> redirection operator or the tee command.
Assuming the file is either nonexistent or both readable and writable, you can try to open it for reading first to determine whether it exists or not, e.g.:
command 3<file 3<&- >>file
3<&-
may be omitted in most cases as it's unexpected for a program to start reading from file descriptor 3
without redirecting it first.
Proof of concept:
$ echo hello 3<file 3<&- >>file
bash: file: No such file or directory
$ ls file
ls: cannot access 'file': No such file or directory
$ touch file
$ echo hello 3<file 3<&- >>file
$ cat file
hello
$
This works because redirections are processed from left to right, and a redirection error causes the execution of a command to halt. So if file
doesn't exist (or is not readable), 3<file
fails, the shell prints an error message and stops processing this command. Otherwise, 3<&-
closes the descriptor (3
) associated with file
in previous step, >>file
reopens file
for appending and redirects standard output to it.
I think a simple if
as proposed in the other answers would be best. However, here are some more exotic solutions:
dd
dd
can do the check and redirection in one step
echo hello | dd conv=nocreat of=file.txt
Note that dd
prints statistics to stderr. You can silence them by appending 2> /dev/null
but then the warning file does not exist
goes missing too.
When you do these kind of redirections very often, then a reusable function would be appropriate. Some examples:
Run echo
and redirect only if the file exists. Otherwise, raise the syntax error -bash: $(...): ambiguous redirect
.
ifExists() { [ -f "$1" ] && printf %s "$1"; }
echo hello >> "$(ifExists file.txt)"
Always run echo
, but print a warning and discard the output if the file does not exist.
ifExists() {
if [ -f "$1" ]; then
printf %s "$1"
else
echo "File $1 does not exist. Discarding output." >&2
printf /dev/null
fi
}
echo hello >> "$(ifExists file.txt)"
Please note that ifExists
cannot handle all file names. If you deal with very unusual filenames ending with newlines, then the subshell $( ...)
will remove those trailing newlines and the resulting file will be different from the one specified. To solve this problem you have to use a pipe.
Always run echo
, but print a warning and discard the output if the file does not exist.
appendIfExists() {
if [ -f "$1" ]; then
cat >> "$1"
else
echo "File $1 does not exist. Discarding output." >&2
return 1
fi
}
echo hello | appendIfExists file.txt
Just check:
if [ -f file.txt ]; then
echo "hello" >> file.txt
else
echo "No file.txt" >&2
exit 1
fi
There's no way in bash
to alter how >>
works; it will always (try to) create a file if it doesn't already exist.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With