0

I want to append things to a file in a way that uses sudo if needed, here's what I have so far :

getAndAppend(){
    # create file if doesn't exist, with right permission
    [[ ! -s $2 ]] && touch "$2" || [[ ! -s $2 ]] && sudo touch "$2" # line 1
    # append stuff to it
    [[ -w $2 ]] && curl -sSL $1 >> $2 || sudo bash -c "curl -sSL $1 >> $2"
    [[ -w $2 ]] && echo -e "\n" >> $2 || sudo bash -c "echo -e \"\n\""
}

file="~/.wot"
url="https://raw.github.com/n-marshall/system-setup/master/common/configs/.gitignore_global"

getAndAppend $url $file

However line 1 doesn't work in that the output will be something like ~/.wot: No such file or directory Then of course the file won't exist and the following lines cannot work properly.

How could I fix that ? Thank you ! Any other comment or approach is welcome of course !

Nicolas Marshall
  • 4,186
  • 9
  • 36
  • 54
  • BTW, `echo -e` is bad form -- any echo implemented following [the POSIX spec](http://pubs.opengroup.org/onlinepubs/009604599/utilities/echo.html) to the letter won't support it (`-n` is not required but allowed, but the only compliant way to handle `-e` is to write the two letters `-e` to stdout). Consider using `printf` instead. (Yes, bash's `echo` is noncompliant by default, but it's not *always* noncompliant -- if both `posix` and `xpg_echo` flags are set it behaves as the standard mandates). – Charles Duffy Sep 02 '16 at 16:12
  • BTW, consider `curl -sSL "$1" | sudo tee -- "$2" >/dev/null` if you need to escalate privileges to write to the file named in `$2` -- there's no need to run `curl` (which, after all, is doing network IO and has a relatively substantial attack surface) as root if all you need the extra privileges for is to open its output file. – Charles Duffy Sep 02 '16 at 16:14
  • Also, you're missing or misusing quotes in a whole bunch of places, and some of those are actively dangerous. `sudo bash -c "curl -sSL $1 >> $2"` is going to do very bad things if `$1` contains, say, `'$(rm -rf $HOME)'`. If you *were* going to escalate privileges for curl, that would need to be `sudo bash -c 'curl -sSL "$1" >>"$2"' _ "$@"` -- which passes the script run with `sudo` privileges as a constant (single-quoted) string, with its arguments out-of-band -- to avoid such shell escapes. – Charles Duffy Sep 02 '16 at 16:18
  • See http://shellcheck.net/ for automated analysis of some of the other (less-finesse-required) quoting mishaps. – Charles Duffy Sep 02 '16 at 16:19
  • Thanks for the suggestions ! Just one thing : Is it not `sudo tee -a "$2"`... to append ? – Nicolas Marshall Sep 02 '16 at 16:26
  • Quite right -- `sudo tee -a -- "$2"`, if you want to work with arbitrary filenames (including those starting with dashes). – Charles Duffy Sep 02 '16 at 16:34
  • Although actually, we can do considerably better than that. Hmm -- I'm almost tempted to write a full answer, albeit to a question other than the one you asked. :) – Charles Duffy Sep 02 '16 at 16:38
  • Which version of bash are you using? (Is it 4.1 or newer?) – Charles Duffy Sep 02 '16 at 16:39
  • ...I've added an appropriate edit (with a completely generic wrapper function that redirects output with `sudo` used when necessary), and hope that it meets with your approval. – Charles Duffy Sep 02 '16 at 16:45

1 Answers1

1
file=~/.wot

or

file="$HOME/.wot"

Quotes prevent tilde expansion.


By the way -- you can do better than plastering sudo in front of every command that needs to emit output to your destination file. Consider:

# Note that this requires bash 4.1 for automatic FD allocation
# otherwise, modify it to hardcode a FD number for our backup.
withOutputToFile() {
  local orig_stdout retval
  exec {orig_stdout}>&1 || return

  if ! exec >"$1"; then
    if ! exec > >(sudo tee -- "$1"); then
      exec >&$orig_stdout
      return 1
    fi
  fi

  shift
  "$@"; retval=$?
  exec >&$orig_stdout {orig_stdout}>&-
  return "$retval"
}

That's a mouthful, sure, but once you have it you can use it to wrap any function:

getAndAppend() {
  curl "$1" && printf '\n'
}

withOutputToFile /path/to/your/file getAndAppend http://example.com/
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441