使用 bash 拆分字符串在 debian 服务器中不起作用

Split string in using bash not working in debian server

我想使用“of”拆分 ins_data 字符串,并将 2 个数字放入 2 个变量中。

我的代码是这样的。

#!/usr/bin/env bash

ins_data="3,998 of 5,903"
IFS=' of ' read -ra ins_data_arr <<< ${ins_data}
total_ins=${ins_data_arr[1]//,}
missed_ins=${ins_data_arr[0]//,}

echo $total_ins
echo $missed_ins

此代码在我的 mac os machine 中运行良好。

但它在 Debian 服务器上不工作。

$ ins_data="3,998 of 5,903"

$ IFS=' of ' read -ra ins_data_arr <<< ${ins_data}
$ declare -p ins_data_arr
declare -a ins_data_arr='([0]="3,998" [1]="" [2]="5,903")'

$ IFS=' of ' read -ra ins_data_arr <<< "$ins_data"
$ declare -p ins_data_arr
declare -a ins_data_arr='([0]="3,998" [1]="" [2]="5,903")'

一开始我发现这种行为很混乱:那个空字段是从哪里来的?我认为 IFS 字符的任何 sequence 都会分隔字段。

这是正确的 IFS 的默认值

这是 IFS 的一个非常微妙的行为,与 Word Splitting 相关:

If IFS has a value other than the default, then sequences of the whitespace characters space, tab, and newline are ignored at the beginning and end of the word, as long as the whitespace character is in the value of IFS (an IFS whitespace character). Any character in IFS that is not IFS whitespace, along with any adjacent IFS whitespace characters, delimits a field. A sequence of IFS whitespace characters is also treated as a delimiter.

因此:零个或多个空格和单个非空格IFS字符分隔字段的序列。

索引 1 处的空数组元素是 "o" 和 "f" 之间的空字符串。

这个测试证实了这个说法:

$ IFS=' of ' read -ra ins_data_arr <<< "3,998 off 5,903"
$ declare -p ins_data_arr
declare -a ins_data_arr='([0]="3,998" [1]="" [2]="" [3]="5,903")'

现在我们在 "o" 和 "f" 之间有一个空字段,在 "f" 和 "f" 之间有一个空字段。

我假设这是 bash 版本 4 的新行为 -- OSX 上的默认 bash 是版本 3.something。行为改变的答案将在这里的某个地方:https://git.savannah.gnu.org/cgit/bash.git/tree/CHANGES?h=bash-4.4


找到了:https://git.savannah.gnu.org/cgit/bash.git/tree/CHANGES?h=bash-4.4#n3970

zz. The word splitting code now treats an IFS character that is not space, tab, or newline and any adjacent IFS white space as a single delimiter, as SUSv3/XPG6 require.

此文档“在此版本、bash-3.1-alpha1、 和以前的版本,bash-3.0-release。”——所以你的 "it works" 版本的 bash 必须 非常 旧。


说了这么多,我推荐的修复方法是:不要使用自定义 IFS,只需考虑到您将阅读 3 个单词的事实:

$ read -r missed of total <<<"$ins_data"
$ declare -p missed of total
declare -- missed="3,998"
declare -- of="of"
declare -- total="5,903"
$ echo "${missed//,/}"
3998
$ echo "${total//,/}"
5903