Append to file only if it exists

后端 未结 4 1174
故里飘歌
故里飘歌 2021-01-18 19:05

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

相关标签:
4条回答
  • 2021-01-18 19:24

    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.

    0 讨论(0)
  • 2021-01-18 19:24

    For example:

    if [ -f "filename" ]; then
    echo "hello" >>filename
    fi
    
    0 讨论(0)
  • 2021-01-18 19:39

    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.

    0 讨论(0)
  • 2021-01-18 19:43

    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
    
    0 讨论(0)
提交回复
热议问题