Added examples of parameter expansion techniques to mimic string indexing

immeëmosol
2025-07-23 12:06:06 +00:00
parent b1b28812ef
commit c766567a4d

103
SC3057.md

@@ -28,25 +28,112 @@ done
printf '%s\n' "${argument-}"
```
An alternative could be to use a delimiting character instead. For instance, to use texts prefixed with a number, an option is to use a colon as a delimiter and use that in a parameter expansion that removes a pattern form either beginning or ending of variable value:
#### Use `parameter expansion` instead
An alternative could be to use parameter expansion instead of string indexing.
Either [through a delimiting character](#through-a-delimiting-character),
[through matching undesired parts of a text](#through-matching-undesired-parts-of-the-text),
or [through a "simple" pattern of `length` size](#through-a-simple-pattern).
##### Through a delimiting character
For instance, to use texts prefixed with a number,
an option is to use a colon as a delimiter
and use that in a parameter expansion
that removes a pattern form either beginning or ending of variable value.
```sh
#!/bin/sh
exitForReasonX='4:Stopping %s because of X.'
exitForReasonY='6:Stopping because of Y.'
echo "The ''reason y'' has number '${exitForReasonY#*:}' and its message is: '${exitForReasonY%%:*}'."
# A more useful example might be :
#!/usr/bin/env sh
exitForReasonY='6:Stopping because of 8x Y.'
printf "The ''reason y'' has number '%s' and its message is: '%s'." "${exitForReasonY#*:}" "${exitForReasonY%%:*}"
```
Or, in a function:
```sh
#!/usr/bin/env sh
exitForReasonX='44:Stopping %s because of X.'
reasonableExit ()
{
state="${1:-}"
state="${state:?is required}"
${1+shift}
>&2 printf '%s\n' "${state%%:*}" ${1+"${@?}"}
exit "${state#*:}"
set -- "${state#*:}" ${1+"${@?}"}
>&2 printf "${@?}"
exit "${state%%:*}"
}
reasonableExit "${exitForReasonX?}" 'something'
```
##### Through matching undesired parts of the text
Another way could be to remove what is unwanted by selecting that.
```sh
#!/usr/bin/env sh
exitForReasonY='6Stopping because of 8x Y.'
yNumber="${exitForReasonY%%[![:digit:]]*}"
yText="${exitForReasonY#${exitForReasonY%%[![:digit:]]*}}"
# or : yText="${exitForReasonY#${yNumber?}"
printf "The ''reason y'' has number '%s' and its message is: '%s'.\n" "${yNumber?}" "${yText?}"
```
Or, in a function:
```sh
#!/usr/bin/env sh
exitForReasonX='44Stopping %s because of X.'
reasonableExit ()
{
text="${1:-}"
text="${text:?is required}"
${1+shift}
state="${text%%[![:digit:]]*}"
set -- "${text#"${state?}"}" ${1+"${@?}"}
>&2 printf "${@?}"
exit "${state?}"
}
reasonableExit "${exitForReasonX?}" 'something'
```
##### Through a "simple" pattern
Remove the smallest _prefix_ from a text where prefix matches a pattern that matches any character as many times as the sum of start and length.
Remove the smallest _suffix that matches that previous text from the original text.
Remove the smallest _prefix_ that matches any character as many times as the start index.
This could also be the other way around, selecting an offset from the end of a text.
```sh
#!/usr/bin/env sh
part="zyxwvutsrqponmlkjihgfedcba"
#echo "${part:5:3}"
part="${part%${part#????????}}"
part="${part#?????}"
printf '%s\n' "${part?}"
```
Code "walkthrough"
```sh
#!/usr/bin/env sh
part="zyxwvutsrqponmlkjihgfedcba"
#echo "${part:5:3}"
part="${part%${part#????????}}"
## Removed smallest prefix from text where prefix matches pattern ????????
## in this case : "rqponmlkjihgfedcba"
## "${part%${part#????????}}" = "${part%"rqponmlkjihgfedcba"}" = "zyxwvuts"
## Removed smallest suffix from part of text where suffix matches pattern ${part#????????} (i.e. "rqponmlkjihgfedcba")
part="${part#?????}"
## Removed smallest prefix from text where prefix matches ????? (i.e. "zyxwv")
printf '%s\n' "${part?}"
```
### Rationale:
String indexing is a bash and ksh extension, and does not work in `dash` or POSIX `sh`.