13

I encountered a git commit which cleans up some readlink and dirname command with this magic variable substitution cd ${0%/*}.

How does bash interpret it?

steveyang
  • 9,178
  • 8
  • 54
  • 80
  • 1
    https://stackoverflow.com/questions/22401091/bash-variable-substitution-vs-dirname-and-basename – Etan Reisner Mar 06 '15 at 07:53
  • http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion – Etan Reisner Mar 06 '15 at 07:54
  • Tangentially, http://stackoverflow.com/questions/4685615/search-engine-for-special-characters wasn't helpful here. I'm sure there are duplicates on StackOverflow but I can't find them. – tripleee Mar 06 '15 at 07:57
  • (But doing `man bash` and searching for just a percent sign will quickly find the relevant documentation.) – tripleee Mar 06 '15 at 07:59

2 Answers2

17

The % here is called pattern-matching operator.

A quote from Learning the Bash Shell book:

The classic use for pattern-matching operators is in stripping off components of pathnames, such as directory prefixes and filename suffixes. With that in mind, here is an example that shows how all of the operators work. Assume that the variable path has the value /home/cam/book/long.file.name ; then:

Expression         Result                                Comments
${path##/*/}                      long.file.name   ## takes out longest matched substring from the front
${path#/*/}              cam/book/long.file.name   # takes out shortest matched substring from the front
$path              /home/cam/book/long.file.name   
${path%.*}         /home/cam/book/long.file        % takes out shortest matched substring from the rear
${path%%.*}        /home/cam/book/long             %% takes out longest matched substring from the rear

These can be hard to remember, so here's a handy mnemonic device:

  • # matches the front because number signs precede numbers;
  • % matches the rear because percent signs follow numbers.

In your specific case, 0 is the counterpart of the path in my example, so you should know it.

If $0 is /home/chj/myfile.txt , cd ${0%/*} will expand to be cd /home/chj, i.e. stripping of the "file" part.

I understand your urge to ask this question, because it is too hard to search for the answer without several hours digging into a Bash book.

Nyubis
  • 528
  • 5
  • 12
Jimm Chen
  • 3,411
  • 3
  • 35
  • 59
10

The command cd ${0%/*} changes directory to the directory containing the script, assuming that $0 is set to the fully-qualified path of the script.

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112