2

This is on OSX El Capitan, but also happens in my Ubuntu aliases as well.

I ran into an issue with an alias I created to pass the working directory to a docker container.

this wont work (always passes ~/Users/username for $(pwd) no matter what directory I'm in):

alias phpqa="docker run --rm -u $UID -v $(pwd):/app eko3alpha/docker-phpqa"

works:

alias phpqa='docker run --rm -u $UID -v $(pwd):/app eko3alpha/docker-phpqa'

However I started getting unexpected errors in my script when the wrong path was being passed in. So I did an experiment. I added both these aliases into my ~/.bash_profile.

alias getpath="echo $(pwd)"
alias getpath2='echo $(pwd)'

I logged off and then logged back in.

Change directory:

$ cd /Users/username/correct/path/to/project

Execute both aliases:

$ getpath
/Users/username

$ getpath2
/Users/username/correct/path/to/project

the alias with the double quotes always returns the users home directory while the alias with single quotes returns the current directory. Can someone explain why that is?

Eko3alpha
  • 540
  • 6
  • 16
  • searching is a useful knowledge. http://stackoverflow.com/questions/6697753/difference-between-single-and-double-quotes-in-bash – Ipor Sircer Sep 20 '16 at 20:03
  • If single quotes were literal then why do I not get "echo $(pwd)" when I execute "getpath2" which is wrapped in single quotes. Instead I get "/Users/username/correct/path/to/project" – Eko3alpha Sep 20 '16 at 20:07
  • It's easy, try yourself: echo "echo $(pwd)" aaaand echo 'echo $(pwd)' Feel the difference? – Ipor Sircer Sep 20 '16 at 20:10
  • Your answers are not addressing my issue as to why $(PWD) is being evaluated differently depending on single vs double quotes in my aliases – Eko3alpha Sep 20 '16 at 20:13
  • 1. its a comment, not answer 2. because this is POSIX, that's the reason. end of story. Ask the old men who wrote POSIX standards 30 years ago. – Ipor Sircer Sep 20 '16 at 20:15
  • 1
    @IporSircer, not that long ago -- POSIX sh dates to the 90s. Though, granted, it was mostly influenced by ksh, which was mostly influenced by Bourne, so we can certainly trace the decisions at hand back to the 70s. – Charles Duffy Sep 20 '16 at 20:48

2 Answers2

5

The alias definition is parsed like any other command. Inside double quotes, variable substitutions like $UID and command substitutions like $(pwd) are expanded. Inside single quotes, nothing is expanded: the only special character is a single quote which terminates the single-quoted literal.

alias phpqa="docker run --rm -u $UID -v $(pwd):/app eko3alpha/docker-phpqa"

Assuming that your user ID is 1000 and the current directory is your home directory /Users/username at the time your .bash_profile is read, this defines the alias phpqa with the expansion docker run --rm -u 1000 -v /Users/username:/app eko3alpha/docker-phpqa.

alias phpqa='docker run --rm -u $UID -v $(pwd):/app eko3alpha/docker-phpqa'

This defines the alias phpqa with the expansion docker run --rm -u $UID -v $(pwd):/app eko3alpha/docker-phpqa. Each time the alias is expanded, it's replaced by the corresponding string and that string is subject to the usual shell parsing rule. So each time the alias is used, the current value of the variable UID is used and the command pwd is executed.

The correct definition of this alias would be

alias phpqa='docker run --rm -u "$UID" -v "$PWD:/app" eko3alpha/docker-phpqa'

Always use double quotes around variable and command substitutions unless you know that you need to omit them. $PWD and $(pwd) are equivalent (the shell tracks the current directory in the variable PWD).

Alternatively, forget about quoting (except for double quotes around substitutions) and use a function.

phpqa () {
  docker run --rm -u "$UID" -v "$PWD:/app" eko3alpha/docker-phpqa "$@"
}
Community
  • 1
  • 1
Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
  • This would explain why I got my home directory vs working directory depending on the types of quotes. Thank you for your explanation! – Eko3alpha Sep 20 '16 at 20:44
  • The function should have `"$@"` at the end to pass through extra arguments (as the alias does). – Charles Duffy Sep 20 '16 at 20:47
  • @Eko3alpha, ...btw, Gilles actually fixed a bunch of bugs in your alias when writing the function version -- it'll work correctly in directories that have spaces in your names, for instance; will explicitly pass an empty string through to `docker run` if `UUID` is undefined rather than running `-u -v` (thus giving a better error message); and is also more efficient since it doesn't bother spawning an unnecessary subshell to run `pwd`. You really should use the function. – Charles Duffy Sep 20 '16 at 20:50
1

The $(pwd) gets evaluated when the alias is created if the alias uses double quotes:

$ alias getpath="echo $(pwd)"
$ alias getpath
alias getpath='echo /Users/username'
$ cd path/to/project
$ getpath
/Users/username

The $(pwd) gets evaluated when the alias is used if the alias uses single quotes:

$ alias getpath='echo $(pwd)'
$ alias getpath
alias getpath='echo $(pwd)'
$ cd path/to/project
$ getpath
/Users/username/path/to/project