I/O
重定向操作符
重定向符 | 功能 | |
---|---|---|
`cmd1 | cmd2` | 管道;接受cmd1 的标准输出,作为cmd2 的标准输入 |
>file |
将标准输出定向到file |
|
<file |
将file 作为标准输入 |
|
>>file |
将标准输出定向到file ,将文件指针置于文件末尾 |
|
`> | file` | 强制重定向(忽略noclobber 状态) |
<>file |
等效于<file >file |
|
<<label |
支持多行输入,直到输入为label 为止 |
|
n>file |
将文件描述符n 定向到file ,n 不写则默认为1 |
|
n<file |
需要从文件描述符n 中读数据时从file 中读,n 不写则默认为0 |
|
n>&m |
将文件描述符n 重定向到文件描述符m 的文件中 |
|
n<&m |
将m 的输入作为n 的输入 |
|
&>file |
等价于>m 2>&1 ,即将标准输出和错误输出都重定向到file中 |
|
/dev/null |
一个特殊的文件,只写不读,当需要丢弃输出时重定向到该文件 |
字符串IO
echo
语句
选项开关
选项 | 功能 |
---|---|
-e |
打印转义字符的解释 |
-E |
(默认)不解释转义字符,直接打印 |
-n |
末尾不打印换行符 |
read
语句
基本格式
1
read var1 var2 ...
该语句从标准输入读取一行,以
IFS
为分隔符分别给var1
var2
等赋值,如有多的字符串,则加在最后一个变量上。选项开关
选项 | 功能 |
---|---|
-a |
读取到数组中 |
-p str |
输入前 |
-r |
使用反斜线作为续行符(这将会忽略转义字符) |
很容易写出按行处理输入的脚本:
1
2
3while read aLine; do
# process the line
doneread
还很适合处理获取用户输入。根据惯例,提示应该被输出到标准错误。
语句块
1 | { |
如上例,可以将一些代码置于{ }
中,便组成了一个语句块,就像它们是一个命令一样。
上述代码实现了从文件读取内容,还有其它方案:
包装成函数,调用函数时指明输入重定向
包装成函数,在函数末尾指明输入重定向
1
2
3
4 > process_line() {
> while ...
> } < somefile
>
在
while
的末尾指明输入重定向
1
2
3
4 > while read aLine; do
> ...
> done < somefile
>
这不仅对
while...done
适用,对任意流控制语句都适用,如if...fi
while...done
case...esac
等等
刚刚发现{ }
妙用的例子:假设a.out
一运行就会报出segmentation fault
的错误,如果使用
1 | $ a.out &> b |
会发现segmentation fault
的报错仍然显示在屏幕上,没有被重定向至b
文件。这是因为这行报错并不是a.out
的标准输出或错误输出,而是由shell
产生的(想一想signal
机制)。要想丢弃这个错误,可以使用{ }
:
1 | $ { a.out &> b; } &> /dev/null |
命令行处理过程
基本步骤
- 分割成记号
- 检测每个命令的第一个记号的类型,查看是不是关键字
- 别名替换(只针对第一个关键字)
- 大括号扩展
~
扩展(包括~+
~user
)- 参数扩展(解析
$
开头的变量) - 命令替换(
$(string)
) - 算数替换(
$((string))
) - 单词分割(使用
IFS
作为分隔符) - 通配符扩展
- 命令查询
- 执行
引用
- 单引号直接绕过前十个步骤
- 双引号绕过 1,2,3,4,9,10
命令查询次序
在bash(上)中提到过,次序为函数、内置命令、脚本、可执行代码,有几个函数可以改变该次序:
command
删除函数查找(删除别名是其副作用)
builtin
只查找内置命令
enable
屏蔽一个内置命令(-n
选项)
enable -n enable
还可以把自己干掉,哈哈哈。好在这时候还可以用builtin
。
再次执行:eval
语句
eval
后面可以跟多个参数,执行时会将它们拼接起来,按照上述12个步骤重新处理一遍
例一:间接执行
1 | object=person |
例二:自定义loop
1 | $ cat myloop |