Search code examples
bashparameter-expansion

How to use parameter expansion correctly in bash


I have a string with the structure task_name-student_name and I want to split it into two variables:

  • task: containing the chunk before the -
  • student: containing the chunk after the -

I can get this to work with sed:

string="task_name-student_name"
student=$(echo "$string" | sed "s/.*-//")
task=$(echo "$string" | sed "s/-[^-]*$//")

However, VS Code suggests "See if you can use $(variable//search/replace) instead".

So I have two questions:

  1. Why would $(variable//search/replace) be better
  2. How do I get the parameter expansion to work without it being interpreted as a command?

When I try

echo $("$string"//-[^-]*$//)

or

echo $(echo $("$string"//-[^-]*$//))

I get this output:

bash: task_name-student_name//-[^-]*$//: No such file or directory

Thanks in advance!


Solution

  • First: for variable expansion, you want curly braces instead of parentheses. $(something) will execute something as a command; ${something} will expand something as a variable. And just for completeness, $((something)) will evaluate something as an arithmetic expression (integers only, no floating point).

    As for replacing the sed with a variable expansion: I wouldn't use $(variable//search/replace} for this; there are more appropriate modifications. ${variable#pattern} will remove the shortest possible match of pattern from the beginning of the variable's value, so use that with the pattern *- to remove through the first "-":

    student=${string#*-}
    

    Similarly, ${variable%pattern} will remove from the end of the variable's value, so you can use this with the pattern -* to remove from the dash to the end:

    task=${string%-*}
    

    Note that the patterns used here are "glob" expressions (like filename wildcards), not regular expressions like sed uses; they're just different enough to be confusing. Also, the way I've written these assumes there's exactly one "-" in the string; if there's a possibility some student will have a hyphenated name or something like that, you may need to modify them.

    There are lots more modifications you can do in a parameter expansion; see the bash hacker's wiki on the subject. Some of these modifications will work in other shells besides bash; the # and % modifiers (and the "greedy" versions, ## and %%) will work in any shell that conforms to the POSIX standard.