我有一个变量 x
,其中包含类似于“2025-12-13-04-32 Hello StackOverflow程序员”的字符串。
我该如何将其拆分成以下几个变量:
d=2015
m=12
dy=13
h=04
mi=32
t="Hello StackOverflow programmers"
我有一个变量 x
,其中包含类似于“2025-12-13-04-32 Hello StackOverflow程序员”的字符串。
我该如何将其拆分成以下几个变量:
d=2015
m=12
dy=13
h=04
mi=32
t="Hello StackOverflow programmers"
一个read
命令就可以完成:
input='2025-12-13-04-32 Hello stackoverflow programmers'
IFS='- ' read -r d m dy h mi t <<<"$input"
<<<
是所谓的here-string,它允许通过stdin提供一个常规的字符串[变量],与多行here-doc(以<<EOF
开头)相关。在这里,它是比echo "$input" | IFS='- ' read ...
更短、更高效的替代方法。
IFS='- '
使read将输入行拆分为令牌,可以是空格或-
。'Hello stackoverflow programmers'
分成3个令牌,但由于read
将行的剩余部分分配给最后指定的变量,以防没有足够的变量来匹配结果的令牌;因此,变量$t
接收'Hello stackoverflow programmers'
,正如所期望的那样。要打印结果,请使用以下代码:
请注意,${!name}
是变量间接引用的一个实例,即通过包含其名称的另一个变量访问变量。
names=( d m dy h mi t )
for name in "${names[@]}"; do
printf '%s=%s\n' "$name" "${!name}"
done
这将产生:
d=2025
m=12
dy=13
h=04
mi=32
t=Hello stackoverflow programmers
关于方法的选择的说明:
read
适用于基于一组文字分隔符进行的基于字段的解析(注意,每个非空格分隔符字符的每个实例都会被计算)。
read -ra
,您甚至可以将所有令牌读入一个数组中,而不必预先知道令牌数量。=~
,如 Jahid's answer所述。使用Bash正则表达式:
#!/bin/bash
s='2025-12-13-04-32 Hello stackoverflow programmers'
pat="([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)[[:space:]]*(.*)"
[[ $s =~ $pat ]]
echo "${BASH_REMATCH[1]}"
echo "${BASH_REMATCH[2]}"
echo "${BASH_REMATCH[3]}"
echo "${BASH_REMATCH[4]}"
echo "${BASH_REMATCH[5]}"
echo "${BASH_REMATCH[6]}"
输出:
2025
12
13
04
32
Hello stackoverflow programmers
=~
实现更灵活的解析; 您还可以按以下方式创建(并打印)各个变量:names=(d m dy h mi t); i=0; for (( i = 0; i < "${#names[@]}"; i++ )); do declare "${names[i]}=${BASH_REMATCH[i+1]}"; printf '%s=%s\n' "${names[i]}" "${!names[i]}"; done
; @Craxxurz: 最好不要使用 for
解析命令输出。 (http://mywiki.wooledge.org/DontReadLinesWithFor) - mklement0x="2025-12-13-04-32 Hello stackoverflow programmers"
read -r d m dy h mi <<< "$x"
但是由于字符串开头包含破折号(-),你需要先将其替换为空格:
x="2025-12-13-04-32 Hello stackoverflow programmers"
x="$(echo "$x" | sed 's/-/ /g')"
read -r d m dy h mi <<< "$x"
你还需要调整变量名的数量 ;-)
我认为这就是你想要的:
x="2025-12-13-04-32 Hello stackoverflow programmers"
x="$(echo "$x" | tr '-' ' ')"
read -r d m dy h mi t <<< "$x"
echo $d
2025
echo $m
12
echo $dy
13
echo $h
04
echo $mi
32
echo $t
Hello stackoverflow programmers
x="${x//-/ }"
。 - Benjamin W.declare
:#!/bin/bash
x="2025-12-13-04-32 Hello stackoverflow programmers"
Shift () {
declare -g "$1=${copy%%-*}"
copy=${copy#*-}
}
copy=$x
for var in d m dy h mi ; do
Shift $var
done
mi=${mi%% *} # Remove the message
t=${copy#* }
for var in d m dy h mi t ; do
echo $var ${!var}
done
declare -g
;没有 -g
,declare
在函数内部创建一个 局部 变量。
通常,简单地省略 declare
也会创建一个全局变量,但由于此处使用参数值作为变量 _名称_,因此需要使用 declare
。
一个在(至少)Bash 3.x 中可用的替代方法是使用 printf -v
创建全局变量:printf -v "$1" %s "${copy%%-*}"
。 - mklement0
echo blah | stuff
,而更类似于 here-doc。除此之外的小细节问题,你的回答在 OP 的情况下绝对是最好的。 - gniourf_gniourf