【问题标题】:split a string on a - delimiter in bash?在bash中的分隔符上拆分字符串?
【发布时间】:2016-10-04 22:31:08
【问题描述】:

如何在 Bash 中根据分隔符拆分字符串?

我将字符串存储在一个变量中,如下所示:

DATA="111111-777777-Hello"

现在我想在- 分隔符上拆分上面的字符串,并将两个数字存储在两个不同的变量中。

NUMBER1="111111"
NUMBER2="777777"

如果 NUMBER1 和 NUMBER2 是空字符串而不是数字,则以非零状态码退出脚本。

【问题讨论】:

  • 在 shell 中为自己的变量使用全大写名称是不好的形式。请参阅pubs.opengroup.org/onlinepubs/009695399/basedefs/…——全大写名称用于对操作系统和 shell 本身有意义的环境变量(设置具有相同名称的 shell 变量将覆盖同名环境变量,即使没有任何尝试 export 它)。避开该命名空间可防止意外覆盖重要的内容。
  • 顺便说一句,既然你有这个标记的 bash,我给出了一个适用于 bash 的答案——如果你想要一些可以与 #!/bin/sh shebang 一起使用的东西,或者以 sh yourscript 而不是 @987654328 运行时@,那就不一样了。
  • 感谢您对所有大写名称的建议。会调查的。是的 bash 是我需要的。

标签: linux bash shell split


【解决方案1】:
IFS=- read -r number1 number2 _ <<<"$DATA"
[[ $number1 && $number2 ]] || { echo "Initial columns not read" >&2; exit 1; }
[[ $number1$number2 = *[![:digit:]]* ]] && { echo "Values are not numeric" >&2; exit 1; }

echo "Number 1 is $number1"
echo "Number 2 is $number2"

IFS 设置为与read 命令在同一行的分隔符(之间没有; 之类的分隔符)将其范围限定为单个read 操作,因此它不会修改shell 的行为脚本中的其他位置。

注意_ 作为read 的额外参数——该行的其余部分存储在那里,防止它被附加到number2

【讨论】:

  • 感谢我们如何检查这些是否只是数字而不是空字符串,然后根据该脚本退出非零状态代码?
  • 修改后演示相同。
  • ...也进行了修改以检查任何非数字数字。
【解决方案2】:

如果你想把它拆分成一个数组使用这个

split() {
    #  split string separator
    #  split a string into an array
    #  the array returned will be newArray
    #  on error return status is 1
    #  usage:- split bash?ksh?zsh?dash ? >>> returns an array of 3 elements bash[0] ksh[1] zsh[2] dash[3]
   local string="${1}" separator="${2}"
   declare cutOneCharacter;
   declare tempvar
   # appending $sepeartor to the ending of $string
   # bacon?tuna?hamburger ? >>>>> if not appeneded the result will be>>>>>> bacon tuna //o_O where is hamburger ?
   # if appeneded the result will be >>>> bacon tuna harmburger 
   string="$string$separator"
   [[ ${newArray[@]} ]] && unset newArray
   splitUsage() {
     echo  "Usage: split string separator" >&2
   }

  (( "${#@}" != "2" )) && splitUsage && return 1;
  while [ -n "${string}" ];do
    cutOneCharacter=$( printf "%c" "$string" )
    if [[ "${cutOneCharacter}" == "${separator}" ]];then
        newArray+=( "${tempvar}" )
        unset tempvar;
    else
        tempvar+="${cutOneCharacter}"
    fi
    string=${string#*?}
  done
  echo"${newArray[@]}"
  return 0;
}

more details are here

【讨论】:

  • 这个实现比split() { IFS="$2" read -r -a newArray &lt;&lt;&lt;"$1"; }增加了什么价值?
【解决方案3】:

使用 bash,操作 IFS

data="111111-777777-Hello"
mapfile -t data < <(IFS=-; printf "%s\n" $data)  # variable is not quoted
echo "${data[0]}"    # 111111
echo "${data[1]}"    # 777777

不要使用全大写变量名——让它们为 shell 保留。

【讨论】:

  • 为了安全起见,我建议在扩展 $data 之前关闭子外壳内的通配符。 (如果设置了nullglob,并且Hello 部分包含[]s、* 等,则可能会使整个扩展结果无效)。
猜你喜欢
  • 2010-10-29
  • 2017-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多