- I/O重定向
默认情况下,有3个“文件”处于打开状态,stdin,stdout,stderr;重定向的解释:捕捉一个文件,命令,程序,脚本或者脚本中的代码块的输出,然后将这些输出作为输入发送到另一个文件,命令,程序或者脚本中。
每个打开的文件都会被分配一个文件描述符,stdin,stdout,stderr的文件描述符分别是0,1,2.除了这3个文件,对于其他需要打开的文件,保留文件描述符3~9.在某些情况下,将这些额外的文件描述符分配给stdin,stdout或stderr作为临时的副本链接也是非常有用的。在经过复杂的重定向和刷新之后需要把他们恢复成正常状态。可以使用shell内建ulimit -n查看最大文件描述符,一般未1024.
ulimit描述如下:
-a All current limits are reported -b The maximum socket buffer size -c The maximum size of core files created -d The maximum size of a process's data segment -e The maximum scheduling priority ("nice") -f The maximum size of files written by the shell and its children -i The maximum number of pending signals -l The maximum size that may be locked into memory -m The maximum resident set size (many systems do not honor this limit) -n The maximum number of open file descriptors (most systems do not allow this value to be set) -p The pipe size in 512-byte blocks (this may not be set) -q The maximum number of bytes in POSIX message queues -r The maximum real-time scheduling priority -s The maximum stack size -t The maximum amount of cpu time in seconds -u The maximum number of processes available to a single user -v The maximum amount of virtual memory available to the shell and, on some systems, to its children -x The maximum number of file locks -T The maximum number of threads
ulimit -a结果如下:
core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 513989 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 4096 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
1 COMMAND_OUTPUT > 2 #将stdout重定向到一个文件,如果这个文件不存在,就创建,否则就覆盖 3 : > filename 4 #将filename变成一个空文件(size=0); 5 # :是一个占位符,不产生任何输出 6 > filename 7 #同上,某些shell可能不支持 8 9 COMMAND_OUTPUT >> 10 #将stdout重定向到一个文件,如果这个文件不存在,就创建,否则就追加 11 1> filename 12 #重定向stdout到filename; 13 1>> filename 14 #重定向并追加stdout到filename; 15 16 M>N 17 #M是文件描述符,默认是1;N是一个文件名;文件描述符M被重定向到文件N 18 19 M>&N 20 #M是文件描述符,默认是1;N是一个文件描述符;文件描述符M被重定向到文件N 21 22 2>&1 23 #重定向stderr到stdout,将错误消息的输出,发送到与标准输出所指向的方向 24 25 i>&j 26 #重定向描述符i到j,默认i是1 27 28 0<FILENAME 29 <FILENAME 30 #从文件中接受输入 31 32 [j]<>filename 33 #为了读写filename,把filename打开,并且将文件描述符j分配给它;如果filename不存在,就创建;如果描述符j没指定,默认fd 0,stdin 34 echo 1234567890 > File # 写字符串到"File". 35 exec 3<> File # 打开"File"并且将fd 3分配给它. 36 read -n 4 <&3 # 只读取4个字符. 37 echo -n . >&3 # 写一个小数点 38 exec 3>&- # 关闭fd 3. 39 cat File # ==> 1234.67890
1 n<&- 2 #关闭输入文件描述符n 3 4 0<&-,<&- 5 #关闭stdin 6 7 n>&- 8 #关闭输出文件描述符n 9 10 1>&-,>&- 11 #关闭stdout
2. 使用exec进行I/O重定向
参考资料:http://www.linuxplus.org/kb/x13380.html
exec <filename命令会将stdin重定向到文件中. 从这句开始, 所有的stdin就都来自于这个文件了, 而不是标准输入(通常都是键盘输入). 这样就提供了一种按行读取文件的方法, 并且可以使用sed和/或awk来对每一行进行分析.
使用exec进行IO重定向可以避免子shell的产生
1 #!/bin/bash 2 #avoid_subshell.sh 3 4 Lines=0 5 echo 6 cat myfile.txt | while read line; #管道会产生子shell 7 do { 8 echo $line 9 (( Lines++ )); #Lines的自加属于子shell范围,外部不能访问 10 echo "in while Lines is $Lines" 11 } 12 done 13 14 echo "Number of lines read = $Lines" #结果为0,显示的结果是错误的 15 echo "------------------------" 16 17 exec 3<> myfile.txt #使用exec打开文件,使用文件描述符3 18 while read line <&3 19 do { 20 echo "$line" 21 (( Lines++ )); #不会产生子shell 22 } 23 done 24 exec 3>&- 25 echo "Number of lines read = $Lines" #Lines输出的值是正确的 26 exit 0
上述代码中应该增加一行"exec 3<&-";原因:使用<>打开文件的读写操作之后,在关闭时,需要分别关闭文件的读和写,需要分开操作。
其中,myfile.txt的内容如下:
1 Line 1. 2 Line 2. 3 Line 3. 4 Line 4. 5 Line 5. 6 Line 6. 7 Line 7. 8 Line 8.
3. 代码块重定向
参考资料:http://www.linuxplus.org/kb/redircb.html
下面是for循环的重定向example:
1 #!/bin/bash 2 3 if [ -z "$1" ] 4 then 5 Filename=names.data # 6 else 7 Filename=$1 8 fi 9 10 #Filename=${1:-names.data} #这句可以代替上面的if语句(参数替换) 11 12 13 Savefile=$Filename.new #保存最终结果的文件 14 FinalName=Jonah #终止“read”时的名称 15 16 line_count=`wc $Filename | awk '{ print $1 }'` #目标文件的行数 17 echo "line_count=$line_count" 18 19 for name in `seq $line_count` #seq会打印出数字序列 20 do 21 read name 22 echo "$name" 23 if [ "$name" = "$FinalName" ] 24 then 25 break 26 fi 27 done < "$Filename" > "$Savefile" #重定向stdin到文件$Filename, 28 # 将输出重定向到$Savefile文件 29 30 exit 0