Search code examples
shellcommand-linefishprepend

How to prepend a file using fish


I saw there were several good answers for bash and even zsh(i.e. Here). Although I wasn't able to find a good one for fish.

Is there a canonical or clean one to prepend a string or a couple of lines into an existing file (in place)? Similar to what cat "new text" >> test.txt do for append.


Solution

  • As part of fish's intentional aim towards simplicity, it avoids syntactic sugar found in zsh. The equivalent to the zsh-only code <<< "to be prepended" < text.txt | sponge text.txt in fish is:

    begin; echo "to be prepended"; cat test.txt; end | sponge test.txt
    

    sponge is a tool from the moreutils package; the fish version requires it just as much as the zsh original did. However, you could replace it with a function easily enough; consider the below:

    # note that this requires GNU chmod, though it works if you have it installed under a
    # different name (f/e, installing "coreutils" on MacOS with nixpkgs, macports, etc),
    # it tries to figure that out.
    function copy_file_permissions -a srcfile destfile
      if command -v coreutils &>/dev/null  # works with Nixpkgs-installed coreutils on Mac
        coreutils --coreutils-prog=chmod --reference=$srcfile -- $destfile
      else if command -v gchmod &>/dev/null  # works w/ Homebrew coreutils on Mac
        gchmod --reference=$srcfile -- $destfile
      else
        # hope that just "chmod" is the GNU version, or --reference won't work
        chmod --reference=$srcfile -- $destfile
      end
    end
    
    function mysponge -a destname
      set tempfile (mktemp -t $destname.XXXXXX)
      if test -e $destname
        copy_file_permissions $destname $tempfile
      end
      cat >$tempfile
      mv -- $tempfile $destname
    end
    
    function prependString -a stringToPrepend outputName
      begin
        echo $stringToPrepend
        cat -- $outputName
      end | mysponge $outputName
    end
    
    prependString "First Line" out.txt
    prependString "No I'm First" out.txt