关于 Word Splitting 和 IFS 的三个细节
在 Bash manual 里叫 Word Splitting,在 Posix 规范里叫 Field Splitting,这两者指的是同一个东西,我把它翻译成“分词”,下面我就说三点很多人都忽略掉(或者说从没仔细考虑过)的分词细节。
1. 分隔符到底是字符还是字符串?
IFS 里面可以包含多个字符,那么在分词的过程中,是 IFS 中的每个单独的字符作为分隔符,还是由这些字符组合成的任意字符串作为分隔符?我们写个简单的例子证明一下:
$ var=a12b21c IFS=12 $ printf "<%s>\n" $var <a> <> <b> <> <c> |
由于输出了两个空的字段,也就证明了是 1 和 2 两个单独的 IFS 字符作为了分隔符,而不是 12 和 21 这两个由 IFS 字符组成的字符串作为了分割符。但结论没这么简单,再看一个例子:
$ var=$'1 \t 2' IFS=$' \t' #红色背景的是空格 $ printf "<%s>\n" $var <1> <2> |
在这个例子中,IFS 包含两个字符:空格符和制表符, 如果说它们俩是单独作为分隔符的,那么 $var 就应该被分割成四个字段,分别是 <1> <> <> <2>,但实际的结果并不是这样的。这是因为:空格符、制表符(\t)、换行符(\n)这三个空白符在 IFS 中会被特殊对待,Shell 会把它们按照任意顺序任意数量组合成的字符串作为分隔符,而不是单个字符作为分隔符。在这个例子中,是“ \t ”整体作为了一个分隔符,把 1 和 2 分成了两个字段。下面再演示一下 IFS 为换行符的情况:
$ var=$'1\n\n\n2\n\n\n3' IFS=$'\n' $ printf "<%s>\n" $var <1> <2> <3> |
这个例子中,三个连续的换行符作为了分隔符,把 var 分成了三个字段。
如果 IFS 既包含空白符,又包含非空白符,会怎么样?
看下面的例子,IFS 中既有空白符 \n 又有非空白符 2:
$ var=$'1\n\n2\n\n3' IFS=$'\n2' $ printf "<%s>\n" $var <1> <3> |
咦?有些同学就想问了:上面不是说,Shell 会把以任意个 IFS 包含的空白符组成的字符串作为分隔符,把单个 IFS 中包含的非空白符作为分隔符吗,那不就是有三个分隔符:“\n\n”、“2”、“\n\n”吗?但从表现上来看,是“\n\n2\n\n”整体作为了一个分隔符,这是怎么回事?
下面我们就再说个法则:“一个 IFS 中包含的非空白符会和它两边存在的由 IFS 中包含的空白符组成的字符串组合成一起作为分隔符”。在上面的例子中,就是 2 和它两边的 “\n\n” 5个字符组合起来作为了一个分割符,所以产生了 1 和 3两个字段。
2. 尾部的空字段会被丢弃
$ var=:1:2:3: IFS=: $ printf "<%s>\n" $var <> <1> <2> <3> |
四个分隔符,应该把 var 切割成 5 个字段,但从结果上看,尾部的空字段不见了?是的,再说一个法则:分词之后,如果最后一个字段是空的,那么这个字段会被丢弃掉。其实,一个包含空值的变量在分词之后会被丢弃,也符合这条法则:
$ var="" $ set -- $var $ echo $# 0 |
上面的例子中,var 的值就是空,所以在分词之后也是只有一个空的字段,也是最后一个字段,符合尾部空字段被丢弃的法则,所以 set 命令只看到了 -- 这一个参数。
3. 首尾的空白符序列会被丢弃掉
$ var=$'\n1:2\n' IFS=$'\n:' $ printf "<%s>\n" $var <1> <2> |
这个例子中,分割符应该有三个,分别是 \n、:、\n,它们会把 var 分割成四个字段 <> <1> <2> <>,尾部的字段是空的,被丢弃,就成了 <> <1> <2>。咦?WTF,为什么和真实的输出不符!下面是最后一条法则:在正式分词之前,变量两边的由 IFS 包含的空白符组合成的序列会被丢弃掉,然后才进行正式分词。在上面的例子中,var 会先被切头去尾,也就变成 “1:2”,才进行正式的分词,也就最终被分成了 1 和 2 两个字段了。注意,首尾的空白符序列只包含由 IFS 中包含的空白符组成的序列,比如上面的例子改一下:
$ var=$'\n1:2\n' IFS=$'\t:' $ printf "<%s>\n" $var < 1> <2 > |
由于 \n 没有包含在 IFS 中,所以 var 首尾的 \n 也就不会被去掉。 关于这点,Bash 的文档记载有 bug,我给提 bug 修复了。
最后说一句,本文中所举的例子都是用 parameter expansion 来演示的,command substitution 和 arithmetic expansion 虽然没有演示,但同样适用。
关于 Word Splitting 和 IFS 的三个细节的更多相关文章
- 从word中提取图片的三种方法
方法1:使用截图方法来提取并保存图片,如果你安装了QQ并且运行了的话,你可以使用Ctrl+Alt+A来截图,然后在QQ聊天框中按CTRL+V来保存图片,当然你可以在PS新建文档按CTRL+V来粘贴图片 ...
- JAX-RS入门 三 :细节
一.若希望一个Java类能够处理REST请求,则这个类必须至少添加一个@Path("/")的annotation:对于方法,这个annotation是可选的,如果不添加,则继承类的 ...
- 我给航母做3D还原:这三处细节,太震撼了…
前两天,我国第三艘航母正式下水,受到国际舆论高度关注.国产福建舰火出了圈,"航母"从军事专业领域,也火到了普通人的视野中. 图源网络 人们一边感叹我国实力强劲,一边对"航 ...
- FastJson反序列化漏洞利用的三个细节 - TemplatesImpl的利用链
0. 前言 记录在FastJson反序列化RCE漏洞分析和利用时的一些细节问题. 1. TemplatesImpl的利用链 关于 parse 和 parseObject FastJson中的 pars ...
- 【转】SHELL中的IFS详解
转自:http://smilejay.com/2011/12/bash_ifs/ 在bash中IFS是内部的域分隔符,manual中对其的叙述如下: IFS The Internal Field Se ...
- shell中的IFS详解
在bash中IFS是内部的域分隔符,manual中对其的叙述如下:IFS The Internal Field Separator that is used for word splitting af ...
- shell IFS
在bash中IFS是内部的域分隔符,manual中对其的叙述如下:IFS The Internal Field Separator that is used for word splitting af ...
- Java Swing 第01记 Hello Word
首先来一个Java Swing的HelloWord程序. package cn.java.swing.chapter03; import javax.swing.JButton; import jav ...
- 第七章 new的三步曲
这章是本系列文章的重点,这章揭示了js对象的真正本质 看下面的事例 var a = new b(); 等价于 ①var a={}; ②a.__proto__=b.prototype; ③b.call( ...
随机推荐
- mysql表复制和修改部分字段
今天在工作中,需要造大量的加数据,1000多条数据如果都是手工输入的话,那么我今天不要干别的了,就造吧! 当时手工操作重复的事情,对程序员来说,是一件很丢人的事情,所以就上网查了一下,需要用到两个知识 ...
- 关于laravel基础知识
laravel任务管理知识点 1.配置数据库环境 首先要找到congif/app.php,在这里会发现一些全局的系统设置,包括语言,时区等. 重要的是会发现前几个数组都使用了env()这个函数,这个时 ...
- 3.bootstrap练习笔记-媒体内容
bootstrap练习笔记-多媒体对象 1.在bootstrap中,如果想存放内容,一种解决的方式就是利用media这个class 首先要设置一个div.container作为一个总的容器来存放内容 ...
- Java开发环境的搭建以及使用eclipse从头一步步创建java项目
一.java 开发环境的搭建 这里主要说的是在windows 环境下怎么配置环境. 1.首先安装JDK java的sdk简称JDK ,去其官方网站下载最近的JDK即可..http://www.orac ...
- js小数点失精算法修正
在用js计算0.07*100时候竟然=7.000000000000001 关于js失精算法你都遇到哪些,让我们一起来细数一下吧 console.log(0.07*100); // 7.00000000 ...
- 【跟着子迟品 underscore】如何优雅地写一个『在数组中寻找指定元素』的方法
Why underscore (觉得这部分眼熟的可以直接跳到下一段了...) 最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中. ...
- JS组件系列——Bootstrap Table 冻结列功能IE浏览器兼容性问题解决方案
前言:最近项目里面需要用到表格的冻结列功能,所谓“冻结列”,就是某些情况下表格的列比较多,需要固定前面的几列,后面的列滚动.遗憾的是,bootstrap table里自带的fixed column功能 ...
- <<Bootstrap基础教程>> 新书出手,有心栽花花不开,无心插柳柳成荫
并非闲的蛋疼,做技术也经常喜欢蛋疼,纠结于各种技术,各种需求变更,还有一个很苦恼的就是UI总是那么不尽人意.前不久自己开源了自己做了多年的仓储项目(开源地址:https://github.com/he ...
- 76 mkswaP-用于设置交换区
Linux mkswap命令用于设置交换区(swap area). mkswap可将磁盘分区或文件设为Linux的交换区. 语法 mkswap [-cf][-v0][-v1][设备名称或文件][交换区 ...
- C语言初级进阶2
运算符 逻辑运算符: && || ! 位运算符:& | ~ ^ 三目运算符: ? : 结构体元素访问: . -> 命令行参数argc与argv C语言中判断式 各种数据类 ...