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.

  • 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 0:05
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'\''\'\'\'\'
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.