使用 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
我想使用“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 charactersspace
,tab
, andnewline
are ignored at the beginning and end of the word, as long as the whitespace character is in the value ofIFS
(anIFS
whitespace character). Any character inIFS
that is notIFS
whitespace, along with any adjacentIFS
whitespace characters, delimits a field. A sequence ofIFS
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