bash脚本中IFS = $'\ n'的含义是什么?


163

bash shell脚本的开头是以下行:

IFS=$'\n'

这些符号集合的含义是什么?


3

vim语法对我来说是一个错误。固定?
theonlygusti '16

IFS=$'\n'是bashism(+其它壳,使用ANSI-C报价,对于解决方法参见stackoverflow.com/questions/10748703/...
pevik

Answers:


199

IFS代表“内部字段分隔符”。外壳使用它来确定如何进行单词拆分,即如何识别单词边界。

在像bash这样的shell中尝试一下(其他shell可能会对此有所不同,例如zsh):

mystring="foo:bar baz rab"
for word in $mystring; do
  echo "Word: $word"
done

的默认值IFS由空格字符组成(准确地说是空格,制表符和换行符)。每个字符可以是一个单词边界。因此,使用默认值IFS,上面的循环将打印:

Word: foo:bar
Word: baz
Word: rab

换句话说,外壳认为空白是一个单词边界。

现在,IFS=:在执行循环之前尝试设置。这次,结果是:

Word: foo
Word: bar baz rab

现在,shell mystring也会拆分为单词-但现在,它仅将冒号视为单词边界。

第一个字符IFS是特殊字符:使用特殊$*变量时,它用于在输出中定界(例如,摘自Advanced Bash Scripting Guide的示例,在该示例中,您还可以找到有关特殊变量的更多信息):

$ bash -c 'set w x y z; IFS=":-;"; echo "$*"'
w:x:y:z

相比于:

$ bash -c 'set w x y z; IFS="-:;"; echo "$*"'
w-x-y-z

请注意,在这两个例子中,shell将仍然把所有的字符:-;作为单词边界。唯一改变的是的行为$*

要知道的另一件重要事情是如何对待所谓的“ IFS空白” 。基本上,只要IFS包含空格字符,就会在处理字符串之前从字符串中剥离前导空格和结尾空格,并使用一系列连续的空格字符来分隔字段。但是,这仅适用于中实际存在的空白字符IFS

例如,让我们来看看字符串"a:b:: c d "(尾随空间和之间有两个空格字符cd)。

  1. 随着IFS=:将它分为四个领域:"a""b"""(空字符串)和" c d "(再次,两者之间的空间cd)。注意最后一个字段中的前导和尾随空格。
  2. 随着IFS=' :',将它分成五个领域:"a""b"""(空字符串),"c""d"。任何地方都没有前导和尾随空格。

请注意,在第二个示例中,多个连续的空白字符如何分隔两个字段,而多个连续的冒号没有分隔字符(因为它们不是空白字符)。

至于IFS=$'\n',这是一个ksh93语法也通过支持bashzshmksh和FreeBSD sh(所有壳之间有变化)。引用bash手册页:

$'string'形式的单词经过特殊处理。该单词扩展为“字符串”,并按ANSI C标准的规定替换反斜杠转义字符。

\n是换行符的转义序列,因此IFS最终被设置为单个换行符。


3
很好,但是,我认为,与bash脚本指南或其他内容相比,阅读和理解POSIX规范要好得多。基本上,在这样的链接上可用的信息缺少重要的方式。无论如何,因此错过了有关外壳拆分的两个关键点-globbing和IFS空白。
mikeserv

@mikeserv谢谢,我在IFS空格上添加了一些信息。对此一无所知。:)
Tblue

4
无关紧要,但是如果您好奇的话,您可能想看看如何unset IFS使Shell行为与完全不同IFS=。此外,IFS中的第一个字节也很特殊"${named_array[*]}"-但在未引用扩展名时也
没关系。– mikeserv

还有几点:1-单词拆分,由控制$IFS是在列表上下文中扩展未引用变量时执行的两个主要操作之一(这splitsplit+glob运算符的一部分)。另一个正在徘徊。使用工作分割时,通常需要发出set -f禁用该glob零件的命令。
斯特凡Chazelas

3
内置命令$IFS也使用3read
StéphaneChazelas 16年

22

在用美元括起来的单引号内,某些字符会被特别评估。例如,\n被翻译为换行符。

因此,此特定行将换行符分配给变量IFS。IFS又是bash中的一个特殊变量:内部字段分隔符。至于man bash说,这

用于扩展后的单词拆分,并使用read内置命令将行拆分为单词。默认值为<space><tab><newline>


5
+1提及dollared single quotes与单引号不同。
Snowcrash

2
@Snowcrash +1表示+1表示美元单引号,这与简单单引号不同。抱歉,无济于事:)但实际上,指出这一点非常好,因为它很重要!
Pryftan

1
@Pryftan +1代表+1 +1 ...您知道...这非常重要。
6

@ 0xc0de绝对同意!感谢那!:)
Pryftan

15

简而言之,IFS=$'\n'将newline分配\n给variable IFS

$'string'构造是一种引用机制,用于解码ANSI C之类的转义序列。这句法来自ksh93,并被移植到现代的外壳一样bashzshpdkshbusybox sh

POSIX未定义此语法,但SUS问题7已接受该语法。


-1

我更喜欢$IFS通过示例进行解释:
Suppsoe您要进行cp或mv或其他文件处理,IFS通过defualt为空,当您的文件包含meta char或空间(如:
Linux Administration.pdf或)时Free Software Fundation.ogg,请确保您具有探针,因为:Linux考虑单独的参数和Administartion考虑单独的参数.bash具有built-in variable,然后您可以初始化为IFS==$(echo -en "\n\b"),然后bash丢弃文件名之间的任何元字符和空格,例如:

#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
mymusicdir=~/test/dd
find $mymusicdir -name "*" -execdir rename 's/ /_/g' "{}" +
IFS=$SAVEIFS
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.