mirror of
https://github.com/koalaman/shellcheck.git
synced 2025-10-03 19:29:44 +08:00
Added examples of parameter expansion techniques to mimic string indexing
103
SC3057.md
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`.
|
||||
|
Reference in New Issue
Block a user