1

我有两个关于IFS. 我知道更改内部字段分隔符IFS会更改 bash 脚本迭代的内容。

那么,为什么数组的长度没有改变呢?

这是我的例子:

delimiter=$1
strings_to_find=$2

OIFS=$IFS
IFS=$delimiter
echo "the internal field separator is $IFS"
echo "length of strings_to_find is ${#strings_to_find[@]}"

for string in ${strings_to_find[@]}
do
    echo "string is separated correctly and is $string"
done

IFS=$OIFS

但是为什么长度不受新 IFS 的影响?

我不明白的第二件事是如何使 IFS 影响输入参数。

假设我希望我的输入参数看起来像这样:

./executable_shell_script.sh first_arg:second_arg:third_arg

我想通过设置来解析输入IFS参数:。我该怎么做呢?设置 IFS 似乎没有做任何事情。我一定做错了……?

谢谢你。

4

2 回答 2

4

Bash 数组实际上就是数组。它们不是按需解析的字符串。一旦你创建了一个数组,元素就是它们本来的样子,它们不会追溯改变。

但是,您的示例中没有任何内容创建数组。如果您想从参数 2 创建一个数组,则需要使用不同的语法:

strings_to_find=($2)

尽管您strings_to_find不是一个数组,但 bash 允许您将它作为一个元素的数组来引用。所以${#strings_to_find[@]}永远是一,不管strings_to_find. 另外,您的线路:

for string in ${strings_to_find[@]}

真的没有什么不同

for string in $strings_to_find

由于该扩展没有被引用,它将使用当前值进行分词IFS

如果你使用数组,大多数时候你不会想写for string in ${strings_to_find[@]},因为这只是将数组的元素重新组合成一个字符串,然后再次对它们进行分词,这会丢失原始的数组结构。通常你会通过使用双引号来避免分词:

strings_to_find=(...)
for string in "${strings_to_find[@]}"

至于你的第二个问题, 的值IFS不会改变 shell 语法。无论 的值如何IFS,命令中的单词都由不带引号的空格分隔。解析行后,shell 对每个单词执行参数和其他扩展。如上所述,如果扩展没有被引用,则扩展文本会使用 的值进行分词IFS

如果单词不包含任何扩展,则不执行分词。即使单词确实包含扩展,单词拆分也仅在扩展本身上执行。所以,如果你写:

IFS=:
my_function a:b:c

my_function将使用单个参数调用;不会发生扩展,因此不会发生分词。但是,如果$1在函数内部使用 unquoted,则扩展 of$1将被分词(如果在发生分词的上下文中扩展)。

另一方面,

IFS=:
args=a:b:c
my_function $args

将导致my_function使用三个参数调用。

最后,

IFS=:
args=c
my_function a:b:$args

与第一次调用完全相同,因为:扩展中没有。

于 2016-06-20T01:45:05.343 回答
2

这是基于@rici的答案的示例脚本:

#!/bin/bash
fun()
{
  echo "Total Params : " $#
}

fun2()
{
  array1=($1) # Word splitting occurs here based on the IFS ':'
  echo "Total elements in array1 : "${#array1[@]}
  # Here '#' before array counts the length of the array
  array2=("$1") # No word splitting because we have enclosed $1 in double quotes
  echo "Total elements in array2 : "${#array2[@]}

}
IFS_OLD="$IFS"
IFS=$':' #Changing the IFS
fun a:b:c #Nothing to expand here, so no use of IFS at all. See fun2 at last
fun a b c
fun abc
args="a:b:c"
fun $args # Expansion! Word splitting occurs with the current IFS ':' here
fun "$args" # preventing word spliting by enclosing ths string in double quotes
fun2 a:b:c

IFS="$IFS_OLD"

输出

Total Params :  1
Total Params :  3
Total Params :  1
Total Params :  3
Total Params :  1
Total elements in array1 : 3
Total elements in array2 : 1

Bash 联机帮助页说:

Shell 将 IFS 的每个字符视为分隔符,并将其他扩展的结果拆分为这些字符上的单词。

于 2016-06-20T02:42:11.767 回答