Bash supports a powerful substring syntax using variable expansion. With the right indizes it's possible to extract
any part of a string. The syntax has 2 forms (example of a variable $str):
${str:position}${str:position:length}
The behavior depends on the syntax used and whether position (pos) and length (len) are positive or negative:
pos |
len |
Extraction start | Extraction end | Example with str='0123456789' |
|---|---|---|---|---|
| < 0 | string end - pos |
string end | ${str: -5} => 56789 |
|
| >= 0 | pos |
string end | ${str:3} => 3456789 |
|
| < 0 | < 0 | string end - pos |
string end - len |
${str: -5:-2} => 567 |
| < 0 | > 0 | string end - pos |
string end - pos + len |
${str: -5:3} => 567 |
| >= 0 | < 0 | pos |
string end - len |
${str:3:-3} => 3456 |
| >= 0 | > 0 | pos |
pos + len |
${str:3:3} => 345 |
It can be helpful to see the extraction limiters like markers which are either a certain number of characters
in the string or a certain amount of characters from the string end. It's as if initially the marker was before the
first character respectively after the last one in case of backward search.
Example: ${str:3:-3} for str='0123456789':
posis 3, ^ is the marker => "012^3456789"lenis -3, ^ is the marker => "0123456^789"- the extracted string is 3456
The examples in the table below shows commands where a space was inserted when position is negative. This is required to avoid a
syntax collision with bash's "default value fallback" syntax ${var:-default} (returns default if $var not set). When a variable is
used, it's not required:
| Code | Result | |
|---|---|---|
| 1 | str='0123456789' |
|
| 2 | minus=-5 |
|
| 3 | echo "\$str: $str - \$minus: $minus" |
$str: 0123456789 - $minus: -5 |
| 4 | echo "\${str:-5}: ${str:-5}" |
${str:-5}: 0123456789 |
| 5 | echo "\${str: -5}: ${str: -5}" |
${str: -5}: 56789 |
| 6 | echo "\${str:\$minus}: ${str:$minus}" |
${str:$minus}: 56789 |
| 7 | echo "\${str:3}: ${str:3}" |
${str:3}: 3456789 |
| 8 | echo "\${str:-5:-2}: ${str:-5:-2}" |
${str:-5:-2}: 0123456789 |
| 9 | echo "\${str: -5:-2}: ${str: -5:-2}" |
${str: -5:-2}: 567 |
| 10 | echo "\${str:\$minus:-2}: ${str:$minus:-2}" |
${str:$minus:-2}: 567 |
| 11 | echo "\${str:-5:3}: ${str:-5:3}" |
${str:-5:3}: 0123456789 |
| 12 | echo "\${str: -5:3}: ${str: -5:3}" |
${str: -5:3}: 567 |
| 13 | echo "\${str:\$minus:3}: ${str:$minus:3}" |
${str:$minus:3}: 567 |
| 14 | echo "\${str:3:-3}: ${str:3:-3}" |
${str:3:-3}: 3456 |
| 15 | echo "\${str:3:3}: ${str:3:3}" |
${str:3:3}: 345 |