详细解析Shell中的IFS变量

您所在的位置:网站首页 英语ifs是什么意思 详细解析Shell中的IFS变量

详细解析Shell中的IFS变量

2024-04-04 15:37| 来源: 网络整理| 查看: 265

Photo by Jacob Postuma on Unsplash

题图:Photo by Jacob Postuma on Unsplash 本文原创发布于微信公众号“洛奇看世界”,一个大龄2b码农的世界

这里的Shell主要指bash,学习bash的前前后后在IFS变量上吃了不少苦头,虽然花了不少时间,也知道大概如何使用,但并没有深入理解。翻了几本Shell相关的书,对IFS也都是一带而过,并没有做详细的阐述(IFS本身在Shell里面就是很小很小的一个知识点而已,也不值得这些书花大篇幅去解释);尝试百度“Shell IFS”,大多数结果也不甚满意。终于决定要自己完整的了解下IFS了。严格来说,本文是对IFS文档描述和使用的考证说明。

本文主要有以下几个话题:

如果想了解我是如何找到介绍IFS资料的,请跳转到第1节,如何找到介绍IFS的资料?如果想知道Bash手册是如何介绍IFS的,请跳转到第2节, Bash手册中关于IFS的介绍;如果想看一些IFS使用相关的例子,请跳转到第3节, IFS使用的一些例子;如果想看一些IFS的结论,请跳转到第4节;如果想了解本文附带有哪些福利,请跳转到第5节; 1. 如何找到介绍IFS的资料?

这个章节挺废话的,但为什么还会有这个章节呢?我只是希望通过这个章节向有些朋友展示我是如何思考,找到解决这个问题的方法的。拿到一个问题,并不是所有朋友都一下子能拿出很好的解决办法,这其中必然有个思考尝试的过程,而这一节,就是想向你展示我是如何思考的。这个过程可能走了很多弯路,并非一下就能找到正确的答案,但仍希望我的思考能对你有一丝的借鉴意义。

想了解IFS,必然需要找到详细的资料才行,可是,如果从来没了解过IFS,从哪里找到介绍IFS的资料呢?

查找资料的第一反应是搜索,但直接以关键字"IFS"/“shell IFS”/"bash IFS"进行百度,得到一大堆告诉你如何使用"IFS"的文章,但这并不是我想要的。

平时习惯了命令行的"man"/“help"方式,但是使用"man IFS”/“help IFS”/"info IFS"都无果啊。

后来想了想,IFS只是Shell里面的一个环境变量,使用"man shell"或"man bash"应该能找到介绍。果不其然,"man bash"找到了关于IFS的介绍。

以下是在"man bash"结果中“Shell Variables”一节关于“IFS”的介绍: 在这里插入图片描述 在"Word Spliting"一节找到更多关于IFS的介绍。 在这里插入图片描述

命令行执行"man bash"显示的内容太多,不方便阅读,后来想到通过"man bash | grep IFS"过滤只与IFS相关的内容,无奈,这个操作没有任何结果。 为什么没有任何结果呢?试着将"man bash"的结果输出到文本文件看看就知道了,里面插入太多显示格式字符,导致连一个完整的IFS字符串都找不到。

因此想到的办法是搜索并下载bash的手册(manual)看看,这样通过bash手册查找IFS相关内容就方便多了。

Bash Reference Manual

在线版:https://www.gnu.org/software/bash/manual/bashref.htmlPDF版:https://www.gnu.org/software/bash/manual/bash.pdf所有版本的入口:https://www.gnu.org/software/bash/manual 2. Bash手册中关于IFS的介绍

这一节看起来也挺废话的,因为其中好多都是直接应用官方文档。我一直认为做技术同做学问一样,都应该是严肃的。这里借用脱袜子大神(torvalds)的一句很有名的话,“Talk is cheap, show me your code”,我想说得是“Talk is cheap, show me your evidence”。所以这一节从官方文档出发,介绍IFS为什么会有这些特性。

本文基于地址“https://www.gnu.org/software/bash/manual/bash.pdf”下载得到的是针对Bash 4.4版本的手册:

This is Edition 4.4, last updated 7 September 2016, of The GNU Bash Reference Manual, for Bash, Version 4.4.

尽管Bash 4.4版本的手册可能跟你运行的bash不匹配,但bash总台上是很稳定的,各版本间差异不会太大,尽管是不同的版本,但也不会影响对IFS内容的理解。

在PDF版的bash手册中搜索“IFS”, 总共在13个章节找到33个结果,其中最重要的地方有4个,包括:

第71页,第5.1节(“5.1 Bourne Shell Variables”)对shell变量IFS的定义第30页,第3.5.7节(“3.5.7 Word Splitting”)对字符分割中使用IFS的介绍第20页,第3.4.2节(“3.4.2 Special Parameters”)对特殊参数使用IFS的介绍第92页,第6.7节(“6.7 Arrays”)对数组引用中使用IFS的介绍

以上列举的4点并非按照先后顺序,而是按照个人理解的重要程度排列

下面详细介绍这4点。

2.1 变量IFS的定义

Bash手册第71页,第5.1节“Bourne Shell Variables”简单说了什么是IFS变量,如下: 在这里插入图片描述 这里提到IFS作为Shell的内置变量,是一个用于分割字段的字符列表(注意,这里是字符列表,说明其中可以包含不止一个字符)。

2.2 使用IFS进行单词分割

Bash手册的第30页,第3.5.7节“Word Splitting”描述了基于IFS进行分割的细节,如下: 在这里插入图片描述 这里说得比较详细,是对IFS工作描述的重中之重,主要有以下几点:

Shell把变量IFS内的每一个字符都当做是一个分割符(delimeter),用这些字符作为每一个字段的结束符来进行分割。如果IFS没有设置,或者IFS的值被设置为“ \t\n”(space, tab和 newline),那么操作对象的开始和结束处的所有space, tab和newline序列都将被忽略,但是操作对象中间的space, tab和newline序列会作为界定符工作。如果IFS值不是默认值(例如程序中对IFS进行设置过),只有出现在IFS内的空白字符(可能是space, tab或newline中的一个或几个)才会在单词开始和结束处被忽略,这里说的是单词,而不是整个操作对象。IFS内的非空白字符多个连续出现时,每个非空白字符会被当做单独的分隔符看待,但是多个连续的空白字符会被当做一个分隔符看待。如果IFS为空(“null”),则不会进行单词分割。 2.3 特殊参数$*中使用IFS

Bash手册的第20页,第3.4.2节“Special Parameters”介绍了特殊参数$*包含在双引号中时,组合的新字符串使用IFS的第1个字符进行连接,由于默认情况下IFS的第1个字符是空格,这就是为什么我们看到"$*"的结果是使用空格进行分隔,如下: 在这里插入图片描述

《Linux命令行与Shell脚本编程大全》第2版的第276页是这样描述$*和$@变量的: $*和$@变量提供了对所有参数的快速访问,这两个都能够在单个变量中存储所有的命令行参数。 $*变量会将命令行上提供的所有参数当做单个单词保存。每个词是指命令行上出现的每个值。基本上,$*变量会将这些都当做一个参数,而不是多个对象。

反过来说,$@变量会将命令行上提供的所有参数当做同一字符串中的多个独立的单词。它允许你便利所有的值,将提供的每个参数分割开来。这通常通过for命令完成。

这里特别说了IFS对变量$*的扩展的影响,主要有3点:

当用双引号(“double quotes”)来引用特殊变量$*时,会使用IFS变量的第1个字符来连接$*参数的每一个部分,即"$*"相当于"$1c$2c...",其中c是IFS变量的第一个字符。如果没有设置IFS,则c为空格字符(space),实际上默认情况下IFS变量的第1个字符就是空格字符。如果IFS为空(null),则$*内各参数会直接连接在一起。 2.4 数组引用中使用IFS

Bash手册的第92页,第6.7节“Arrays”介绍了IFS对数组元素引用的影响,如下: 在这里插入图片描述 这里强调引用数组元素时,还可以使用和@下标,哈哈,没想到吧,跟命令行参数一样。 通常情况下是使用带下标的 n a m e [ s u b s c r i p t ] 方 式 引 用 , 但 现 在 还 可 以 使 用 ‘ ∗ ‘ 和 ‘ @ ‘ 来 引 用 , 如 ‘ {name[subscript]}方式引用,但现在还可以使用`*`和`@`来引用,如` name[subscript]方式引用,但现在还可以使用‘∗‘和‘@‘来引用,如‘{name[]}和 n a m e [ @ ] ‘ 。 如 果 ‘ {name[@]}`。 如果` name[@]‘。如果‘{name[]}被包含在双引号内,则其将会用IFS的第1个字符连接数组的各个元素进行扩展,跟上1节使用双引号引用特殊参数$`一样。

3. IFS使用的一些例子

关于IFS的重点: IFS是shell的内置变量,IFS是一个字符列表,里面的每一个字符都会用来作为分隔符进行单词分割。

以下是使用IFS设置和分割的一些例子。

3.1 检查IFS的默认值 mbp:~ rocky$ echo -n "$IFS" | hexdump 0000000 20 09 0a 0000003

十六进制值0x20, 0x09和0x0a分别对应于空格(space), 水平制表符(tab)和换行符(newline)的值。

这里给echo使用“-n”参数避免在echo时在行位添加换行符。如下是不带“-n”的输出:

mbp:~ rocky$ echo "$IFS" | hexdump 0000000 20 09 0a 0a 0000004

跟前面的结果比较,这里最后多了一个字符0x0a。

3.2 IFS的修改和恢复

因为IFS是系统级变量,修改使用后记得要恢复原样,否则后续程序就会出现一些奇奇怪怪的异常,别怪我没告诉你啊,我自己曾经因为这个问题踩了个大坑。

这里以一个处理带空格的文件名来展示对IFS变量的修改。

操作目录下有一个名为"a b c.txt"的文件(字母a,b,c中间有两个空格):

mbp:shell rocky$ ls -lh total 24 -rw-r--r-- 1 rocky admin 0B 5 6 01:21 a b c.txt drwxr-xr-x 3 rocky admin 442B 5 6 02:03 images -rw-r--r-- 1 rocky admin 115B 5 6 02:04 test1.sh -rw-r--r-- 1 rocky admin 202B 5 6 02:02 test2.sh -rw-r--r-- 1 rocky admin 228B 5 6 02:03 test3.sh 默认情况,无法处理文件名中的空格 mbp:shell rocky$ cat test1.sh #!/bin/bash echo "1.Test with default IFS:" echo -n "$IFS" | hexdump for item in `ls` do echo "file: $item" done mbp:shell rocky$ mbp:shell rocky$ bash test1.sh 1.Test with default IFS: 0000000 20 09 0a 0000003 file: a


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3