0

I read "Linux Bible 10th Edition", chapter 7: Writing Simple Shell Scripts, at 149 page, "Parameter expansion in bash" paragraph.

  • ${var:-value} — If variable is unset or empty, expand this to value.
  • ${var#pattern} — Chop the shortest match for pattern from the front of var’s value.
  • ${var##pattern} - Chop the longest match for pattern from the front of var’s value.
  • ${var%pattern} — Chop the shortest match for pattern from the end of var’s value.
  • ${var%%pattern} - Chop the longest match for pattern from the end of var’s value.

Please, explain to me, how the longest/shortest match is calculated? From right to the left or vice versa?

Also, explain please, how code below is working and how output is calculated

MYFILENAME=”/home/digby/myfile.txt”—Sets the value of MYFILENAME 
FILE=${MYFILENAME##*/}—FILE becomes "myfile.txt" 
DIR=${MYFILENAME%/*}—DIR becomes "/home/digby" 
NAME=${FILE%.*}—NAME becomes "myfile" 
EXTENSION=${FILE##*.}—EXTENSION becomes "txt"

Thank you.

1
  • 2
    Does not removing from the front or end of a string implicitly say it's from the left or right? For your second issue (please, only one issue per question!), the answer is that it follows the rules that you have just previously laid out. I'm not turning this into an answer, because it's unclear what the issue is and what type of answer is sought. Should the answer talk about how the parameter expansions are implemented in the bash source code, or should it just point out the rules that are applied, that are already found in the question text?
    – Kusalananda
    Commented Apr 9, 2022 at 9:44

1 Answer 1

2

Let's start with the "#" case which chops from the front. Consider a string such as myfile.tar.gz. If you match this against the string *. (which means "zero or more characters" followed by a full stop) then there are two possible matches: myfile. and myfile.tar.. The shortest match is:

${MYFILENAME#*.} # ie myfile.

so the result is what is left: tar.gz. The longest match is:

${MYFILENAME##*.} # ie myfile.tar.

so the result is what is left: gz.

Now consider the "%" case. Here matching is on the right of the string. This time match with .*. We are looking for a dot with some (or none) characters after it. The shortest match is .gz and the longest .tar.gz so we get:

${MYFILENAME%.*}  # => myfile.tar
${MYFILENAME%%.*} # => myfile

Your other examples are variations on a theme to illustrate this:

MYFILENAME=”/home/digby/myfile.txt”—Sets the value of MYFILENAME 
FILE=${MYFILENAME##*/}—FILE becomes "myfile.txt" 
DIR=${MYFILENAME%/*}—DIR becomes "/home/digby" 
NAME=${FILE%.*}—NAME becomes "myfile" 
EXTENSION=${FILE##*.}—EXTENSION becomes "txt"

interpreted:

  1. The longest string matching */ from the front is /home/digby/
  2. The shortest string matching /* at the end is /myfile.txt
  3. The shortest string matching .* at the end is .txt
  4. The longest string matching "*.at the front ismyfile.`

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .