【问题标题】:Bash - saving string to separate variable after custom delimiterBash - 在自定义分隔符后将字符串保存到单独的变量
【发布时间】:2018-01-22 15:28:57
【问题描述】:

我对 Bash 还很陌生,所以请原谅我,但我正在构建一个可以接受用户输入命令的 Bash 脚本,该命令可以有很多开关。我需要编写一个从用户提供的命令中提取特定数据的函数。

我似乎无法找到一种方法来提取“-mode”之后的每个单词并将其推送到某种数组或列表中。

以下是用户输入命令的示例:

/home/custom/function/that/accepts/a/billion/switches  random_info random_info2 -worker vendor_schmo  -switch_one  -anotherOne  -more_switches  -optionTwo        -mode FOO -mode BAR -mode BAZ -mode BAG -mode DAT -mode RAR

我试过摆弄 awk -F "-mode" '{ print $1 }' 但没有奏效。任何建议将不胜感激!

这是提取此信息的脚本中的 sn-p:

manualRunMain(){
  local command
  manualRunHeaderPrint
  echo
  echo
  echo
  echo
  lineBreakPrint
  read -p "Enter your command here: " command
  sleep .25
  manualRun "$command"
}

manualRun(){
  manualRunHeaderPrint
  jobRunSubHeaderPrint
  pullModeNames "$1"
}

pullModeNames(){

}

【问题讨论】:

  • 欢迎来到堆栈溢出,您能否在代码标签中添加示例预期输出?
  • 我认为我不需要任何输出,我只需要将每个“-mode”之后的每个单词推入一个数组即可。我认为这就足够了,我可以从那里拿走它。
  • 一般来说,您应该考虑遵循BashFAQ #35 中给出的做法来满足您的特定目的。您的命令给出的参数列表不是作为字符串传递——而是作为字符串数组传递——并且将其视为字符串意味着你采用了一堆错误(例如例如,您将失去区分 -foo "bar baz"-foo bar baz 的能力。
  • (如果你有一个字符串并且需要以一种类似于 shell 的方式将它拆分成一个字符串列表,这样就可以使用标准工具解析该数组,这本身就是一个相当复杂的问题,其答案array=( $string )复杂得多;也就是说,它一个已经存在公认的规范答案的问题在我们的知识库中)。

标签: string bash parsing scripting


【解决方案1】:

您可以在 awk 中使用 RS 变量来告诉在获得 -mode 时将数据拆分为单独的记录:

s='/home/custom/function/that/accepts/a/billion/switches  random_info random_info2 -worker vendor_schmo  -switch_one  -anotherOne  -more_switches  -optionTwo        -mode FOO -mode BAR -mode BAZ -mode BAG -mode DAT -mode RAR'

printf '%s' "$s" | awk -v RS="-mode[[:space:]]*" 'NR>1'
FOO
BAR
BAZ
BAG
DAT
RAR

填充数组:

mapfile -t arr < <(printf '%s' "$s" | awk -v RS="-mode[[:space:]]*" 'NR>1')

# examine array content
declare -p arr
declare -a arr=([0]="FOO" [1]="BAR" [2]="BAZ" [3]="BAG" [4]="DAT" [5]="RAR")

【讨论】:

  • 谢谢!太棒了。我会支持你,但我还没有声望这样做:)
  • 请注意,填充数组的命令会受到分词和全局扩展的影响,因此如果您有参数-mode 'has space',它将中断。相反,您可以使用 mapfile: mapfile -t arr &lt; &lt;(awk -v RS="-mode" 'NR&gt;1{ print $1 }' &lt;&lt;&lt; "$s")
  • @BenjaminW.:很好,但是如果有任何空格,那么即使print $1 也只会打印第一部分。
  • 既然您使用的是RS,您不能首先打印$0 吗?可能必须调整 RS 才能吞下空格。类似RS="-mode *"
  • 顺便说一句,我同意这是对标题中提出的问题的最佳答案,但问题文本(命令行解析)中给出的预期用例让我对这个答案是否适合目的。
【解决方案2】:

我刚刚想出了与@anubhava 基本相同的答案,但使用的是 GNU grep 而不是 awk:

$ cmd="... -more_switches  -mode FOO BAR -mode BAZ -mode BAG -mode CAT DAT HAT -mode RAR"
$ mapfile -t modes < <(grep -oP -- '-mode \K.+?(?= -mode|$)' <<<"$cmd")
$ printf "%s\n" "${modes[@]}"
FOO BAR
BAZ
BAG
CAT DAT HAT
RAR

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-30
    • 1970-01-01
    相关资源
    最近更新 更多