How to prepend a file using fish

Viewed 676

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.

2 Answers

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

For the specific case that file size is small to medium (fit in memory), consider using the ed program, which will avoid the temporary files by loading all data into memory. For example, using the following script. This approach avoid the need to install extra packages (moreutils, etc.).

#! /usr/env fish
function prepend
  set t $argv[1]
  set f $argv[2]
  echo '0a\n$t\n.\nwq\n' | ed $f
end
Related