Naveen Dennis
Naveen Dennis

Reputation: 1223

What is the difference between % and %% in shell scripting?

In bash scripting, when t="hello.txt" both

${t%%.txt} and ${t%.txt} returns "hello"

the same goes for ${t##*.} and ${t#*.} returns "txt".

Is there a difference between them? How do they work?

Upvotes: 2

Views: 5130

Answers (2)

Sam Watkins
Sam Watkins

Reputation: 8359

In short, %% removes as much as possible, % as little as possible.

# t="hello.world.txt"
# echo ${t%.*}
hello.world
# echo ${t%%.*}
hello

From the bash manual:

'${PARAMETER%WORD}'
'${PARAMETER%%WORD}'
     The WORD is expanded to produce a pattern just as in filename
     expansion.  If the pattern matches a trailing portion of the
     expanded value of PARAMETER, then the result of the expansion is
     the value of PARAMETER with the shortest matching pattern (the '%'
     case) or the longest matching pattern (the '%%' case) deleted.  If
     PARAMETER is '@' or '*', the pattern removal operation is applied
     to each positional parameter in turn, and the expansion is the
     resultant list.  If PARAMETER is an array variable subscripted with
     '@' or '*', the pattern removal operation is applied to each member
     of the array in turn, and the expansion is the resultant list.

Upvotes: 2

user3978398
user3978398

Reputation:

${string%substring}
Deletes shortest match of $substring from back of $string.

For example:

# Rename all filenames in $PWD with "TXT" suffix to a "txt" suffix.
# For example, "file1.TXT" becomes "file1.txt" . . .

SUFF=TXT
suff=txt

for i in $(ls *.$SUFF)
do
  mv -f $i ${i%.$SUFF}.$suff
  #  Leave unchanged everything *except* the shortest pattern match
  #+ starting from the right-hand-side of the variable $i . . .
done ### This could be condensed into a "one-liner" if desired.

${string%%substring}
Deletes longest match of $substring from back of $string.

stringZ=abcABC123ABCabc
#                    ||     shortest
#        |------------|     longest

echo ${stringZ%b*c}      # abcABC123ABCa
# Strip out shortest match between 'b' and 'c', from back of $stringZ.

echo ${stringZ%%b*c}     # a
# Strip out longest match between 'b' and 'c', from back of $stringZ.

Upvotes: 1

Related Questions