Bash 分析while read循环的IFS参数时出现错误?如果不是,为什么?

Bash 分析while read循环的IFS参数时出现错误?如果不是,为什么?,bash,Bash,我有一个带有一些数据的制表符分隔的文件。我正在处理它,一次读取一行到一个数组中。但是,解析此命令的IFS参数时存在一些严重问题 下面这个简短的例子可以在几个bash版本和几个Windows/cygwin、linux和BSD系统中重现 假设我想打印每一行,每一行都有类似表格的框架(这不相关-阅读相关): 我得到的结果是: | 1 | 2 | 3 | 4 | 5 | 6 | 多次尝试后,获得预期行为的唯一方法是重写全局IFS变量(为了子shell中封装的合理性): 问题是:

我有一个带有一些数据的制表符分隔的文件。我正在处理它,一次读取一行到一个数组中。但是,解析此命令的IFS参数时存在一些严重问题

下面这个简短的例子可以在几个bash版本和几个Windows/cygwin、linux和BSD系统中重现

假设我想打印每一行,每一行都有类似表格的框架(这不相关-阅读相关):

我得到的结果是:

|  1  |  2  |  3  |  4  |  5  |  6  |
多次尝试后,获得预期行为的唯一方法是重写全局IFS变量(为了子shell中封装的合理性):


问题是:为什么IFS参数/变量的行为如此怪异?它背后有什么逻辑吗?-或者-我遗漏了什么吗?

如果
的行为与预期的完全一样。几乎所有Unix类型系统上的默认
IFS
都是“空格键换行符”。一般认为:

IFS=$' \t\n'

在原始情况下,
IFS=echo-e“12 3\t4 5\t6”
,您可以取消设置
IFS
,然后调用
echo
。默认值应用于空间。然后明确地设置
IFS=$'\t'
,它正确地将字段分隔/分词限制在
选项卡
字符上,并获得所需的结果。

IFS
的行为与预期的完全相同。几乎所有Unix类型系统上的默认
IFS
都是“空格键换行符”。一般认为:

IFS=$' \t\n'

在原始情况下,
IFS=echo-e“12 3\t4 5\t6”
,您可以取消设置
IFS
,然后调用
echo
。默认值应用于空间。然后明确地设置
IFS=$'\t'
,它正确地将字段分隔/分词限制在
选项卡
字符上,并获得所需的结果。

IFS
的行为与预期的完全相同。几乎所有Unix类型系统上的默认
IFS
都是“空格键换行符”。一般认为:

IFS=$' \t\n'

在原始情况下,
IFS=echo-e“12 3\t4 5\t6”
,您可以取消设置
IFS
,然后调用
echo
。默认值应用于空间。然后明确地设置
IFS=$'\t'
,它正确地将字段分隔/分词限制在
选项卡
字符上,并获得所需的结果。

IFS
的行为与预期的完全相同。几乎所有Unix类型系统上的默认
IFS
都是“空格键换行符”。一般认为:

IFS=$' \t\n'

在原始情况下,
IFS=echo-e“12 3\t4 5\t6”
,您可以取消设置
IFS
,然后调用
echo
。默认值应用于空间。然后明确设置
IFS=$'\t'
,将字段分隔/分词正确限制为
选项卡
字符,并获得所需的结果。

您的脚本几乎正确:

$ printf '%s\t' "1 2 3" "4 5" "6" |
> while IFS=$'\t' read -r -a array ; do
>   for field in "${array[@]}" ; do
>     printf '|  %s  ' "$field"
>   done
>   printf '|'
> done
|  1 2 3  |  4 5  |  6  |


“${array[@]}”
必须被引用才能准确保留数组边界。

您的脚本几乎正确:

$ printf '%s\t' "1 2 3" "4 5" "6" |
> while IFS=$'\t' read -r -a array ; do
>   for field in "${array[@]}" ; do
>     printf '|  %s  ' "$field"
>   done
>   printf '|'
> done
|  1 2 3  |  4 5  |  6  |


“${array[@]}”
必须被引用才能准确保留数组边界。

您的脚本几乎正确:

$ printf '%s\t' "1 2 3" "4 5" "6" |
> while IFS=$'\t' read -r -a array ; do
>   for field in "${array[@]}" ; do
>     printf '|  %s  ' "$field"
>   done
>   printf '|'
> done
|  1 2 3  |  4 5  |  6  |


“${array[@]}”
必须被引用才能准确保留数组边界。

您的脚本几乎正确:

$ printf '%s\t' "1 2 3" "4 5" "6" |
> while IFS=$'\t' read -r -a array ; do
>   for field in "${array[@]}" ; do
>     printf '|  %s  ' "$field"
>   done
>   printf '|'
> done
|  1 2 3  |  4 5  |  6  |


“${array[@]}”
必须被引用才能准确地保留数组边界。

对于${array[@]}中的字段
字符串会分割字段。您需要对“${array[@]}”中的字段使用带引号的
来保留边界……也就是说,您的解析非常好,但在输出端却弄糟了。对于${array[@]}中的字段,字符串会分割字段。您需要对“${array[@]}”中的字段使用带引号的
来保留边界……也就是说,您的解析非常好,但在输出端却弄糟了。对于${array[@]}中的字段,字符串会分割字段。您需要对“${array[@]}”中的字段使用带引号的
来保留边界……也就是说,您的解析非常好,但在输出端却弄糟了。对于${array[@]}中的字段,字符串会分割字段。你需要在“${array[@]}”的字段中使用带引号的
来保留边界……也就是说,你的解析很好,但是你在输出端把它搞乱了……但是用户没有看到他们想要的结果——他们看到的是
|1 | 2 | 3 | 4 | 5 | 6
,而他们期望的是
.1 | 2 | 3 | 4 | 5
,于是问题来了。现在你把我弄糊涂了。我读到的全部要点是,在不稳定的
IFS
之后,获得
|1 | 2 | 3 |
而不是
|1 | 2 | 3
时存在着“惊喜”。OP使用
IFS=$'\t'
获得了所需的结果。问题是“第一次发生了什么?”和“这背后有什么逻辑吗?”也许我只是变老了:)@charlesduff-我明白你在说什么,我同意这个问题是在输出端引用的。-而我正在变老……但用户没有看到他们想要的结果——他们看到的是
|1 | 2 | 3 | 4 | 5 | 6
,而他们期望的是
|1 2 3 | 4 5 | 6
,因此问题就来了。现在你把我弄糊涂了。我读到的全部要点是,在不稳定的
IFS
之后,获得
|1 | 2 | 3 |
而不是
|1 | 2 | 3
时存在着“惊喜”。OP使用
IFS=$'\t'
获得了所需的结果。问题是“第一次发生了什么?”和“这背后有什么逻辑吗?”也许我只是变老了:)@charlesduff-我明白你在说什么,我同意这个问题是在输出端引用的。-而我正在变老……但用户看不到结果