How to split one string into multiple variables in bash shell?
我一直在寻找解决方案,发现了类似的问题,只是他们试图用空格分割句子,答案不适合我的情况。
当前正在将一个变量设置为如下字符串:
ABCDE-123456
我想把它分成两个变量,同时去掉"-"。即:
var1=ABCDE
var2=123456
怎样才能做到这一点?
这是对我有效的解决方案:
var1=$(echo $STR | cut -f1 -d-)
var2=$(echo $STR | cut -f2 -d-)
是否可以使用不带分隔符的CUT命令(每个字符都被设置为变量)?
var1=$(echo $STR | cut -f1 -d?)
var2=$(echo $STR | cut -f1 -d?)
var3=$(echo $STR | cut -f1 -d?)
etc.
- 对于您的第二个问题,请参见下面@mkb对我的答案的评论-这绝对是一条必经之路!
- 查看我编辑的答案,了解将单个字符读取到数组中的一种方法。
- 这里有一个更简洁的形式:var1=$(cut-f1-d-<<<$str)
read和IFS是完美的:
1 2 3 4 5
| $ IFS=- read var1 var2 <<< ABCDE-123456
$ echo"$var1"
ABCDE
$ echo"$var2"
123456 |
编辑:
以下是如何将每个单独的字符读取到数组元素中:
1
| $ read -a foo <<<"$(echo"ABCDE-123456" | sed 's/./& /g')" |
转储数组:
1 2
| $ declare -p foo
declare -a foo='([0]="A" [1]="B" [2]="C" [3]="D" [4]="E" [5]="-" [6]="1" [7]="2" [8]="3" [9]="4" [10]="5" [11]="6")' |
如果字符串中有空格:
1 2 3
| $ IFS=$'\v' read -a foo <<<"$(echo"ABCDE 123456" | sed 's/./&\v/g')"
$ declare -p foo
declare -a foo='([0]="A" [1]="B" [2]="C" [3]="D" [4]="E" [5]="" [6]="1" [7]="2" [8]="3" [9]="4" [10]="5" [11]="6")' |
- 太好了,优雅的巴什只有办法,没有不必要的叉子。
- 此解决方案的好处是,如果不存在分隔符,则var2将为空。
如果您知道它只是两个字段,那么可以跳过这样的额外子流程:
1 2
| var1=${STR%-*}
var2=${STR#*-} |
这是做什么的?${STR%-*}删除与模式-*匹配的$STR的最短子串,从字符串的末尾开始。${STR#*-}也做同样的事情,但使用*-模式,从字符串的开头开始。它们都有对应的%%和##,它们找到了最长的锚定模式匹配。如果有人有一个有用的助记法来记住哪一个做的,请告诉我!我总是要努力记住这两个。
- 另外,1用于了解POSIX外壳的特性,避免昂贵的分叉和管道,以及缺少bashims。
- 不知道"没有bashism",考虑到这已经相当神秘了……如果分隔符是换行符而不是连字符,那么它会变得更加神秘。另一方面,它适用于换行,所以就是这样。
- 描述一下它的实际工作原理会很有帮助
- @克兰森:完成
- 解释得很好。谢谢。此功能的正式名称是什么?有相关文件吗?
- 我终于找到了它的文档:shell参数扩展
- 最好的答案。
- 助记键:""在标准键盘上位于"%"的左侧,因此""删除前缀(在左侧),"%"删除后缀(在右侧)。
- 最简单的答案,适用于零修改。谢谢您!
如果您的解决方案不必是一般性的,即只需要对像您的示例这样的字符串有效,则可以执行以下操作:
1 2
| var1=$(echo $STR | cut -f1 -d-)
var2=$(echo $STR | cut -f2 -d-) |
我在这里选择了cut,因为您可以简单地将代码扩展为更多的变量…
- 你能再看一下我的帖子,看看你是否有后续问题的解决方案吗?谢谢!
- 您也可以使用cut来剪切字符!例如,cut -c1。
- 虽然这是一个非常简单的读写方式,但速度非常慢的解决方案,因为这会迫使你读两倍相同的数据($str)。如果您关心脚本的性能,@anubhava解决方案要好得多。
- 除了是一个丑陋的最终解决方案外,这还有一个缺陷:除非您特别希望shell扩展字符串中的任何通配符作为副作用,否则在echo"$STR"中应该绝对使用双引号。另请参见stackoverflow.com/questions/10067266/&hellip;
- 当然,关于双引号,你是对的,尽管我确实指出了这个解决方案不是一般的。不过,我认为您的评估有点不公平——对于某些人来说,此解决方案可能比其他解决方案更具可读性(因此也更具可扩展性等),并且不完全依赖不会转换为其他shell的奥术bash功能。我怀疑这就是为什么我的解决方案虽然不那么优雅,但仍会定期获得选票的原因…
听上去像是一个为set定制的IFS工作。
1 2 3 4
| IFS=-
set $STR
var1=$1
var2=$2 |
(您将希望在使用local IFS的函数中执行此操作,这样就不会把脚本中要求IFS达到预期效果的其他部分搞得一团糟。)
- 很好-我知道$IFS,但还没有看到它是如何使用的。
- 我用了Triplee的例子,它和广告中的效果完全一样!如果需要用几个"抛出的"变量在整个脚本中存储它们,只需将最后两行更改为
1
| myvar1=<wyn>echo $1</wyn> && myvar2=<wyn>echo $2</wyn> |
。
- 不,不要在背景中使用无用的echo。
- 如果我们需要写一些不特定于bash的东西,这是一个非常好的解决方案。为了解决IFS的问题,可以在覆盖之前在开始添加OLDIFS=$IFS,然后在set行之后添加IFS=$OLDIFS。
- @Danielandersson如果您不想或不能使用local IFS的函数(反正也不是完全可移植的),那么这也是一个很好且常见的解决方法。
使用bash regex功能:
1 2 3 4
| re="^([^-]+)-(.*)$"
[["ABCDE-123456" =~ $re ]] && var1="${BASH_REMATCH[1]}" && var2="${BASH_REMATCH[2]}"
echo $var1
echo $var2 |
产量
1 2 3 4 5
| string="ABCDE-123456"
IFS=- # use"local IFS=-" inside the function
set $string
echo $1 # >>> ABCDE
echo $2 # >>> 123456 |
- 嗯,这不是对我答案的重申吗?
- 事实上是的。我只是澄清了一下。