首页 > 代码库 > 《学习bash》笔记--输入输出
《学习bash》笔记--输入输出
1.I/O重定向符
I/O重定向符如下:
- cmd1 | cmd2:管道,接收cmd1的标准输出作为cmd2的标准输入。
- >file:将标准输出定向到file
- <file:从file接收标准输入
- >>file:将标准输出定向到file,如果file存在则附加在后面
- >|file:即使设置了noclobber仍然强制标准输出到file。
shell提供了一种称为noclobber的特性,该特性可防止重定向时不经意地重写了已存在的文件。通过设置变量noclobber可以
将此特 性打开。打开后若将输出重定向到某个已存在文件,则shell将报告错误消息,并且不执行重定向命令。
例如:
root@-virtual-machine:~# cat a.txt
123
root@virtual-machine:~# set -o | grep "noclobber"
noclobber off
root@virtual-machine:~# echo "test1" > a.txt
root@virtual-machine:~# cat a.txt
test1
root@virtual-machine:~# set -o noclobber
root@virtual-machine:~# set -o | grep "noclobber"
noclobber on
root@gmdz-virtual-machine:~# echo "hello" > a.txt
-bash: a.txt: 无法覆盖已存在的文件
root@virtual-machine:~# echo "hello" >| a.txt
root@virtual-machine:~# cat a.txt
hello
- n>|file:即使设置了noclobber仍强制从文件描述符n中输出到file。
例如:
root@-virtual-machine:~# cat a.txt
123
root@virtual-machine:~# set -o | grep "noclobber"
noclobber off
root@virtual-machine:~# ls nosuchfile 2> a.txt
root@virtual-machine:~# cat a.txt
ls: 无法访问nosuchfile: 没有那个文件或目录
root@virtual-machine:~# echo "123" > a.txt
root@virtual-machine:~# cat a.txt
123
root@virtual-machine:~# set -o noclobber
root@virtual-machine:~# set -o | grep "noclobber"
noclobber on
root@virtual-machine:~# ls nosuchfile 2> a.txt
-bash: a.txt: 无法覆盖已存在的文件
root@virtual-machine:~# cat a.txt
123
root@virtual-machine:~# ls nosuchfile 2>| a.txt
root@virtual-machine:~# cat a.txt
ls: 无法访问nosuchfile: 没有那个文件或目录
- <>file:使用file同时作为输入和输出。
- n<>file,以读写方式打开file,并将n重定向到该文件。
要说明这个重定向符之前,先要说明exec命令:
shell的内建命令exec将并不启动新的shell,而是用要被执行命令替换当前的shell进程,并且将老进程的环境清理掉,而且exec命令
后的其它命令将不再执行。因此,如果你在一个shell里面,执行exec ls那么,当列出了当前目录后,这个shell就自己退出了,因为这个
shell进程已被替换为仅仅执行ls命令的一个进程,执行结束自然也就退出了。不过,要注意一个例外,当exec命令来对文件描述符操
作的时候,就不会替换shell,而且操作完成后,还会继续执行接下来的命令。
- $ exec 3<>file
- $ ls >&3
- $ cat file
- file
- $ cat <&3
- $ exec 3<>file
- $ cat <&3
- file
到3,会打印出file的内容。由上面的结果还能看到exec 3<> file只针对一条指令有效。
- n>file,以写式打开file,并将n重定向到该文件。
例如:
root@gmdz-virtual-machine:~/test# exec 3> file
root@gmdz-virtual-machine:~/test# ls >& 3
root@gmdz-virtual-machine:~/test# cat file
a
b
root@gmdz-virtual-machine:~/test# cat <& 3
cat: -: 错误的文件描述符
- n<file,以读式打开file,并将n重定向到该文件。
例如:
root@virtual-machine:~/test# cat file
test
root@virtual-machine:~/test# exec 3< file
root@virtual-machine:~/test# ls >& 3
ls: 写入错误: 错误的文件描述符
root@virtual-machine:~/test# cat <& 3
test
root@virtual-machine:~/test# cat <& 3
root@virtual-machine:~/test#
同样,exec 3< file只针对一条指令有效。
- <<label:here-document
<<label重定向符强制一个命令的输入使用shell的标准输入,并一直读到仅含label的行。期间的输入称为here-document
例如:
# cat > msgfile << EOF
> 1
> 2
> 3
> EOF
root@gmdz-virtual-machine:~/test# cat msgfile
1
2
3
重定向<<有两个变体,首先,你可以通过把label括在单引号或双引号内防止shell进行参数和命令替换,例如:
root@virtual-machine:~/test# cat << EOF
> $PWD
> EOF
/root/test
root@virtual-machine:~/test# cat << "EOF"
> $PWD
> EOF
$PWD
第二个变体是<<-,它从here-document和标签行中删除前导TAB(但不删除空格)。
例如脚本内容如下:#!/bin/bash
cat <<- EOF
123
456
EOF
执行后,输出为:
123456
- n>> file:将文件描述符n定向到file,如果file存在则附加到后面,例如:command 2>> file
- n>& :将标准输出复制到文件描述符n
- n<& :从文件描述符n复制标准输入
- n>&m:使文件描述符n成为输出文件描述符m的副本
例如:
root@virtual-machine:~/test# cat file
test
root@virtual-machine:~/test# ls nosuchfile
ls: 无法访问nosuchfile: 没有那个文件或目录
root@virtual-machine:~/test# ls nosuchfile > file 2>&1
root@virtual-machine:~/test# cat file
ls: 无法访问nosuchfile: 没有那个文件或目录
- n<&m:使文件描述符n成为输入文件描述符m的副本
- &>file:定向标准输出和错误输出到file。
例如:
root@virtual-machine:~/test# ll a nosuchfile &> file
root@virtual-machine:~/test# cat file
ls: 无法访问nosuchfile: 没有那个文件或目录
-rw-r--r-- 1 root root 0 2014-08-01 09:09 a
- <&-:关闭标准输入
例如有如下脚本:
exec <&-
cat
执行结果:
# ./a.sh
cat: -: 错误的文件描述符
cat: 关闭标准输入: 错误的文件描述符
- >&-:关闭标准输出
例如有如下脚本:
exec >&-
echo "test"
执行结果:
# ./a.sh
./a.sh: 第 2 行: echo: 写错误: 错误的文件描述符
- n>&-:关闭从文件描述符n的输出
例如:
root@gmdz-virtual-machine:~# ls
a.sh file test
root@virtual-machine:~# exec 3<> file
root@virtual-machine:~# ls >&3
root@virtual-machine:~# exec 3<> file
root@virtual-machine:~# exec 3>&-
root@virtual-machine:~# ls >&3
-bash: 3: 错误的文件描述符
- n<&-:关闭从文件描述符n的输入
例如:
root@gmdz-virtual-machine:~# exec 3<> file
root@gmdz-virtual-machine:~# cat <&3
a.sh
file
test
root@virtual-machine:~# exec 3<> file
root@virtual-machine:~# exec 3<&-
root@virtual-machine:~# cat <&3
-bash: 3: 错误的文件描述符
2.字符串I/O
2.1.echo
echo将其参数简单地打印到标准输出上。echo接收短划线选项,如下表。
-e:打开斜线转义字符的解释
-E:关闭子系统上反斜线转义字符的解释,此为默认模式。
-n:省略最后的换行
例如:
root@virtual-machine:~# echo -e "a\ta"
a a
root@virtual-machine:~# echo -E "a\ta"
a\ta
root@virtual-machine:~# echo -n "a\ta"
a\taroot@virtual-machine:~#
2.2.read
read允许你将值读到shell变量中,基本语法是:
read var1 var2 ...
该语句从标准输入中接收一行,将其分开形成单词,单词间用环境变量IFS的值中的任意字符分隔。单词然后被赋值到变量
var1,var2...
例如,a.sh的内容为:
read v1 v2
echo $v1
echo $v2
执行结果:
# ./a.sh
123 456
123
456
如果单词比变量多,则额外的单词被赋值到最后的变量中,如果你省略了变量,则整个输入被赋值到变量REPLY中。
例如,再次执行上面的脚本:
# ./a.sh
1 2 3 4
1
2 3 4
修改a.sh的内容为:
read
echo $REPLY
执行结果为:
# ./a.sh
1 2 3 4
1 2 3 4
下面介绍如下从文件中读取变量。
例如,file文件内容如下:
arg1-1 arg1-2
arg2-1 arg2-2
arg3-1 arg3-2
方法一:
使用如下a.sh脚本可以进行变量的读取:
while read v1 v2;do
echo $v1 $v2
done
执行结果:
# ./a.sh < file
arg1-1 arg1-2
arg2-1 arg2-2
arg3-1 arg3-2
方法二:
修改a.sh:
while read v1 v2;do
echo $v1 $v2
done < file
执行结果:
# ./a.sh
arg1-1 arg1-2
arg2-1 arg2-2
arg3-1 arg3-2
方法三:
修改a.sh:
func(){while read v1 v2;do
echo $v1 $v2
done
}
func < file
执行结果:
# ./a.sh
arg1-1 arg1-2
arg2-1 arg2-2
arg3-1 arg3-2
方法四:
修改a.sh:
{while read v1 v2;do
echo $v1 $v2
done
} < file
执行结果:
# ./a.sh
arg1-1 arg1-2
arg2-1 arg2-2
arg3-1 arg3-2
read有3个常用选项:-a,-p和-r。
-a允许你将值读到一个数组中,每个连续的条目读取都被赋值到以下标0开始的给定数组中,例如a.sh内容如下:
read -a people
echo ${people[0]} ${people[1]} ${people[2]}
执行结果:
# ./a.sh
1 2 3
1 2 3
-p选项在读取输入前打印该字符串,例如:
[root@yanPC ~]# read -p "dir?" dirname
dir?/home
[root@yanPC ~]# echo $dirname
/home
-r选项在读取输入时不忽略“\”字符。
如果"\"在输入字符串的内部:
[root@yanPC ~]# read dirname
123\456
[root@yanPC ~]# echo $dirname
123456
[root@yanPC ~]# read -r dirname
123\456
[root@yanPC ~]# echo $dirname
123\456
如果"\"在输入字符串的最后:
[root@yanPC ~]# read dirname
123\
> 456
[root@yanPC ~]# echo $dirname
123456
[root@yanPC ~]# read -r dirname
123\
[root@yanPC ~]# echo $dirname
123\