1

I have a complex command that I'm running in watch to nag users to get out of a filesystem when I need to unmount it. The following is working

watch -ben5 $'lsof /mnt/unfs && ps --no-headers -o tty -p `lsof -F p0 /mnt/unfs | sed -e "s/p//"` | xargs -I terms sudo sh -c \'echo -ne "\\n\\e[97;101mGET OUT OF UNFS\\e[31;49m cd ~ \\e[97;101mNOW!\\e[39;49m\\n" >/dev/terms\''`

But now I'd like to define an alias for it, and I can't seem to figure out how to "count quotes" as the answerer of Wrapping a command that includes single and double quotes for another command says. The shell ends up trying to execute parts of the echo text.

Jeff
  • 1,282
  • 5
    Use function instead of alias – Costas Jul 24 '15 at 19:03
  • Using a function is the best answer. But when you have many levels of quotes, you can always pass something to printf "%q" \'whatever\' and then cut and paste the response. – user3188445 Jul 25 '15 at 00:05

1 Answers1

1

It's easier if you spread it out a little:

watch -ben5 '
    lsof /mnt/unfs &&
    ps    -o tty= -p "$(lsof -F p0 /mnt/unfs | sed -e "s/p//")" |
    xargs -I terms sudo sh -c '\''
        printf "\n\33[97;101m%s\33[31;49m%s\33[97;101m%s\33[39;49m\n" \
               "GET OUT OF UNFS" " cd ~ " "NOW!" >/dev/terms'\'''

It's pretty difficult for me to understand what's going on here exactly. But if you wanted to put that in an alias, it's pretty simple: you just add another '. Here's a trick:

alias myalias="$(cat <<\IN
watch -ben5 '
    lsof /mnt/unfs &&
    ps    -o tty= -p "$(lsof -F p0 /mnt/unfs | sed -e "s/p//")" |
    xargs -I terms sudo sh -c '\''
        printf "\n\33[97;101m%s\33[31;49m%s\33[97;101m%s\33[39;49m\n" \
               "GET OUT OF UNFS" " cd ~ " "NOW!" >/dev/terms'\'''
IN
)"

The here-document is another form of shell-quote. And all quotes can be contained within hardquotes except hardquotes. So you can go as many levels deep as you like by finding every occurrence of a hardquote and escaping it. By which I mean turning every ' into '\''. After you've done so, you can wrap the entire statement in another layer of quotes. And in fact, alias does this for you:

alias myalias

myalias='    watch -ben5 '\''
    lsof /mnt/unfs &&
    ps    -o tty= -p "$(lsof -F p0 /mnt/unfs | sed -e "s/p//")" |
    xargs -I terms sudo sh -c '\''\'\'\''
        printf "\n\33[97;101m%s\33[31;49m%s\33[97;101m%s\33[39;49m\n" \
               "GET OUT OF UNFS" " cd ~ " "NOW!" >/dev/terms'\''\'\'\'\'
mikeserv
  • 58,310