如何逐个字符串迭代,然后使用不同的分隔符(在bash中)通过这些单词

时间:2016-06-01 17:40:41

标签: bash

如果我有以下字符串:

1234-56-78 17:38:00,00 [main]

我想隔离第二个',

17:38:00,00

然后解析这个词(显然是一个时间戳)来隔离17和38中的每个并将它们放到变量中,我该怎么做?在获得时间时,我尝试了以下方法:

stampLine="1234-56-78 17:38:00,00 [main]"
array=("$stampLine")
fullStamp=${array[1]}
IFS=':' read -ra splitStamp <<< $fullStamp
stampArray=($splitStamp)
x=${stampArray[0]}
echo ${x#0} # to strip leading zeroes

以及:

declare -i index
for item in $array; do
  if [ index == 1 ]; then
    fullStamp=$item
    IFS=':' read -ra splitStamp <<< $fullStamp
    stampArray=($splitStamp)
    x=${stampArray[0]}
    echo ${x#0} # to strip leading zeroes
  fi
done

但他们两个都失败了,这让我来到这里。如果有人能够回答这个问题和/或解释我失踪的内容,我会非常感激。

3 个答案:

答案 0 :(得分:3)

你使它变得不必要地复杂。这应该足够了:

stampLine="1234-56-78 17:38:00,00 [main]"
read date time tag <<< "${stampLine}"
IFS=: read hours minutes seconds <<< "${time}"
echo ${hours}
echo ${minutes}

当然,如果你只想一步完成,这就行了,因为IFS是一组用于分词的字符,而不仅仅是一个字符:

IFS=" -:" read x x x hours minutes x <<< "${stampLine}"

如果你真的关心其他值,那么在它们的位置使用其他变量是必需的,但如果你不这样做,让shell重新使用“虚拟”变量是有用的......

答案 1 :(得分:1)

您第一次尝试的片段:

stampLine="1234-56-78 17:38:00,00 [main]"
array=("$stampLine")

...不能做你想要的,因为你引用了$stampLine的扩展,从而防止扩展受到分词的影响。如果删除第二行中的引号(如果$IFS具有合适的值,例如其默认值),则$array将初始化为三元素数组。

下面:

fullStamp=${array[1]}
IFS=':' read -ra splitStamp <<< $fullStamp

...使用read内置函数和here-string是相当重要的。我想重点是本地化$IFS的修改值,但你可以采用其他方式。例如,您可以将原始值保存在其他变量中,然后将其还原。但就个人而言,我可能倾向于使用local $IFS副本声明一个函数:

split_HMS() {
  local IFS=':'
  splitStamp=($1)
}

# ...

fullStamp=${array[1]}
split_HMS $fullStamp

您的第二个示例遇到了额外的问题,即虽然您声明变量$index,但您从不为其分配任何值。因此,测试[ $index == 1 ]永远不会成功。

特别是回答您的问题,

  

[怎么可能]我想隔离第二个'字'[...]然后解析   这个词(显然是一个时间戳)隔离了每个17和38和   把它们变成变量[...]?

我可以用这种方式组装:

parseTime() {
  local IFS=':'
  local hms=($2)
  hour=${hms[0]#0}
  minute=${hms[1]#0}
}

stampLine="1234-56-78 17:08:00,00 [main]"
parseTime $stampLine

echo "hour:   $hour"
echo "minute: $minute"

输出:

hour:   17
minute: 8

答案 2 :(得分:1)

correct answertwalberg之外,我建议:

简短方法

stampLine="1234-56-78 17:38:00,00 [main]"
IFS=$' \n\t:' read day hre min sec foo <<<"$stampLine"

echo $day
1234-56-78
echo $hre
17
echo $min
38
echo $sec
00,00
echo $foo
[main]

当然在第二行,IFS可能是=' :',但我更喜欢这样做,以避免引导可能造成的换行或不需要的标签 read工作不对。

步骤详细方式

stampLine="1234-56-78 17:38:00,00 [main]"
read date time foo <<<$stampLine
IFS=:, read hrs min sec frac <<<$time

echo $foo
[main]
echo $time
17:38:00,00
echo $frac
00
echo $sec 
00
echo $min
38
echo $hrs
17

关于 bash正则表达式

的一句话

对于这种用法,与使用read 正则表达式相比,有两个成功[[ "$stampLine" =~ ... ]],就像在第二个示例中一样,可以更快地完成任务。

...甚至三个read IFS=- read year month day <<<$date的{​​{1}}将保持更快减少CPU加热器然后使用 bash's正则表达式