我有两个关于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似乎没有做任何事情。我一定是做错了吗?
谢谢。
答案 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的每个字符视为分隔符,并将其拆分 其他扩展到这些角色的文字的结果。