为什么IFS不会影响bash中数组的长度?

时间:2016-06-20 00:30:18

标签: bash find ifs

我有两个关于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似乎没有做任何事情。我一定是做错了吗?

谢谢。

2 个答案:

答案 0 :(得分:3)

Bash数组实际上是数组。它们不是按需解析的字符串。创建数组后,元素就是它们的任何元素,它们不会追溯性地改变。

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

strings_to_find=($2)

虽然你的strings_to_find不是一个数组,但是bash允许你引用它,好像它是一个元素的数组。因此,无论${#strings_to_find[@]}的内容如何,​​strings_to_find始终为1。你的行:

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未加引号,则$1的扩展将被分词(如果它在发生分词的上下文中展开)。

另一方面,

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

将使用三个参数调用my_function

最后,

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

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

答案 1 :(得分: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的每个字符视为分隔符,并将其拆分   其他扩展到这些角色的文字的结果。