bash中如何正确使用参数展开

How to use parameter expansion correctly in bash

我有一个结构为 task_name-student_name 的字符串,我想将它分成两个变量:

我可以让它与 sed 一起工作:

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

但是,VS Code 建议“看看你是否可以使用 $(variable//search/replace) 代替”。

所以我有两个问题:

  1. 为什么 $(variable//search/replace) 会更好
  2. 如何在不将其解释为命令的情况下使参数扩展起作用?

当我尝试时

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

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

我得到这个输出:

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

提前致谢!

首先:对于变量扩展,你需要花括号而不是圆括号。 $(something) 将执行 something 作为命令; ${something} 将扩展 something 作为变量。为了完整起见,$((something)) 会将 something 计算为算术表达式(仅整数,无浮点数)。

至于用变量扩展替换 sed:我不会为此使用 $(variable//search/replace};还有更合适的修改。 ${variable#pattern} 将从变量值的开头删除 pattern 的最短可能匹配项,因此将其与模式 *- 一起使用以删除第一个“-”:

student=${string#*-}

类似地,${variable%pattern} 将从变量值的 end 中删除,因此您可以将其与模式 -* 一起使用以从破折号中删除到最后:

task=${string%-*}

请注意,这里使用的模式是 "glob" expressions(如文件名通配符),而不是像 sed 使用的正则表达式;它们只是不同到令人困惑。另外,我写这些的方式假设字符串中只有一个“-”;如果有可能某些学生会有带连字符的名字或类似的东西,您可能需要修改它们。

您可以在参数扩展中进行更多修改;见bash hacker's wiki on the subject。除了 bash 之外,其中一些修改还适用于其他 shell; #% 修饰符(以及“贪心”版本 ##%%)将在任何符合 [=45= 的 shell 中工作]标准。