Cutting Strings Without External Tools
A very common task in ops scripting is parsing strings: extracting a filename from a path, stripping a file extension, or isolating a date from a filename. Beginners often reach for cut, awk, or sed for this. Bash can do it natively, which is faster (no subprocess) and more portable.
The key operators are #, ##, %, and %%. Here is the mnemonic:
#and##remove from the front (left side) of the string%and%%remove from the end (right side) of the string- Single character (
#,%) = shortest match (non-greedy) - Double character (
##,%%) = longest match (greedy)
Removing from the front: given a full path like /var/log/nginx/access.log, the shortest-match form strips up to the first /, while the longest-match form strips up to the last / — which leaves just access.log, the same result as calling basename, but without spawning a separate process.
Removing from the end: given a filename like image.tar.gz, the shortest-match form strips just the last extension (leaving image.tar), while the longest-match form strips everything from the first dot onward (leaving image).
Substring extraction works like a slice: ${var:offset:length} pulls a fixed-length chunk starting at a given offset.
Search and replace follows the same single-vs-double pattern as the trimming operators: a single / replaces only the first match, a double // replaces every match in the string.