Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Append to file only if it exists

Tags:

bash

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.

like image 942
doobeedoobee Avatar asked Jun 12 '20 12:06

doobeedoobee


People also ask

Does append create a file if it doesn't exist?

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.

Does append mode create new file?

Open file in append mode. If file does not exist, it creates a new file. This is the default mode.

How do I add text to a file in bash?

Conclusion. In Linux, to append text to a file, use the >> redirection operator or the tee command.


3 Answers

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.

like image 52
oguz ismail Avatar answered Oct 16 '22 18:10

oguz ismail


I think a simple if as proposed in the other answers would be best. However, here are some more exotic solutions:

Using 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.

Using a custom Function

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
like image 6
Socowi Avatar answered Oct 16 '22 18:10

Socowi


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.

like image 2
chepner Avatar answered Oct 16 '22 20:10

chepner