Step 1 of 5 · Reading · ~3 min
Learn
Strings and Output
Strings
By the end of this lesson you can build strings, measure and slice them, and cut prefixes and suffixes off a value with the shell's own built-in tools. Everything in bash is already a string, so "string handling" means two tiers: parameter expansion (built into the shell, instant) and delegating to programs such as tr and cut. Reach for the built-in first.
Building strings
Concatenation is adjacency, with no operator:
first="Ada"
full="$first Lovelace" # Ada Lovelace
greeting="Hello, ${first}!" # braces mark where the name ends
greeting+=" Welcome." # += appends text to a variable
Double quotes are the default for building text: they expand variables and keep spacing.
Measuring and slicing
Everything lives inside ${ }. Try these on s="hello world":
echo "${#s}" # 11 length (the # goes INSIDE the braces)
echo "${s^^}" # HELLO WORLD uppercase; ${s^} only the first letter
echo "${s,,}" # hello world lowercase
echo "${s:0:5}" # hello offset 0, length 5
echo "${s:6}" # world from offset 6 to the end
echo "${s/world/bash}" # hello bash replace the first match
echo "${s//o/0}" # hell0 w0rld replace every match
Cutting prefixes and suffixes
Four forms remove text that matches a glob pattern (* means any text, ? any one character; not a regular expression) from one end of the value:
| Form | Removes | Match |
|---|---|---|
${v#pat} | from the front | shortest |
${v##pat} | from the front | longest |
${v%pat} | from the back | shortest |
${v%%pat} | from the back | longest |
On a keyboard # sits left of $ (the front) and % to its right (the back). One character means the shortest match, two mean the longest.
ver="v2.14.7"
echo "${ver#v}" # 2.14.7 drop the leading v
echo "${ver%.*}" # v2.14 shortest suffix that looks like .something
echo "${ver%%.*}" # v2 longest suffix that looks like .something
echo "${ver##*.}" # 7 longest prefix that looks like something.
The longest and shortest forms differ only when the pattern can match in more than one way, and that is exactly when you need to choose. Real data is full of it:
url="https://example.com/docs/guide.html"
rest="${url#*://}" # example.com/docs/guide.html
host="${rest%%/*}" # example.com
Programs for streams of text
Some jobs want the toolbox, which the pipes lesson covers properly: echo "$s" | tr 'a-z' 'A-Z' translates characters and echo "$s" | cut -d' ' -f1 takes the first space-separated field. Rule of thumb: expansions for one variable's worth of text, programs for streams of lines. Starting a process for every string operation in a loop is the classic slow script.
Common mistakes
${s#}for the length. The length is${#s}.${s#}strips an empty prefix and prints the string unchanged, and$#sis the argument count followed by the letter s.- Cutting the wrong string.
${v%.*}removes from the end of the whole value. If the value contains a path, a dot in a directory name can be the one that matches; cut the file name off first, then work on that. - Treating patterns as regular expressions.
${v%.*}means "a dot, then anything". It is a glob. - Mixing up the doubled forms.
%.*and%%.*give different answers ona.b.c:a.bversusa.
Your exercise
Split a file path into the directory it lives in, the file name without its extension, and the extension. The extension is the text after the last dot. Do the splitting with parameter expansion, and keep an eye on dots that belong to directory names.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…