-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathredirection_exec
More file actions
180 lines (166 loc) · 8.37 KB
/
redirection_exec
File metadata and controls
180 lines (166 loc) · 8.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
重定向输出的格式:
1. COMMAND_OUTPUT > FILE # 重定向命令标准输出到文件FILE
2. COMMAND_OUTPUT >> FILE # 重定向命令标准输出追加到文件FILE
3. : > FILE # 将文件FILE置空,若FILE不存在则创建空文件
4. > FILE # 同上
5. 1> FILE # 同1
6. 1>> FILE # 同2
7. 2> FILE # 重定向标准错误输出到文件FILE
8. 2>> FILE # 重定向标准错误输出追加到文件FILE
9. &> FILE # 重定向标准输出和标准错误输出到文件FILE
10. M> FILE # 将文件描述符M重定向到文件FILE,M默认为1
11. M>& N # 将文件描述符M重定向到文件描述符N,M默认为1
12. < FILE # 重定向标准输入为FILE
13. 0< FILE # 同上
14. [j]<> FILE # 以可读可写打开文件,并分配文件描述符为j,若j未指定,默认为0
15. n<& - # 关闭输入描述符n
16. 0<& - # 关闭标准输入
17. <& - # 同上
18. n>& - # 关闭输出描述符n
19. 1>& - # 关闭标准输出
20. >& - # 同上
eg:
1) 将标准错误重定向到与标准输出重定向的相同地方:
bad_command >> FILE 2>&1 # 将命令bad_command标准输出追加到文件FILE,若出错,则将错误信息重定向到FILE中
2) 将标准错误重定向到标准输出
bad_command 2>& 1 | awk '{print $4}' # 通过管道发送标准错误输出,在bash4中,2>& 1有一个缩写 |&
3) 同时重定向标准输入和标准输出
command < INPUT_FILE > OUTPUT_FILE # 重定向命令command的标准输入为INPUT_FILE,标准输出为OUTPUT_FILE
4) 重定向顺序不同会有不同的效果
ls -yz >> OUT_FILE 2>&1 # 将标准错误和标准输出都重定向到文件OUT_FILE中
ls -yz 2>&1 >> OUT_FILE # 将标准错误输出重定向到标准输出,将标准输出重定向到OUT_FILE中
5) >&- echo "close stdout" # 报描述符的写错误
6) <&- read # 报描述符的读错误
7) 子进程可以继承打开的文件描述符,为了防止描述符被继承,可以关闭它
exec 3>&1 # 打开描述符3,重定向到标准输出
ls -l 2>&1 >&3 3>&- | grep bad 3>&- # 前一个3>&-关闭描述符3,防止grep继承
exec 3>&- # 关闭描述符3,之后的脚本将无法再使用该描述符
注:以上的重定向仅仅影响的是当前命令的输入输出
使用exec重定向:
1. exec > FILE # 重定向标准输出为文件FILE(即为FILE打开一个输出描述符1),从该命令后,所有的标准输出都重定向为FILE
2. exec N> FILE # 为FILE打开一个输出文件描述符N
3. exec N>& M # 将描述符N关联到输出描述符M,即为输出描述符M创建一个副本描述符N
4. exec N>&- # 关闭输出描述符N
5. exec >&- # 关闭标准输出描述符
6. exec < FILE # 重定向标准输入为文件FILE(即为FILE打开一个输入描述符0)从该命令后,所有的标准输入都重定向为FILE
7. exec N< FILE # 为FILE打开一个输入描述符N
8. exec N<& M # 将描述符N关联到输入描述符M,即为输入描述符M创建一个副本描述符N
9. exec N<&- # 关闭输入描述符N
10. exec <&- # 关闭标准输入描述
11. exec N<> FILE # 为FILE打开一个可读可写文件描述符N,关闭时需要分别关闭读和写
eg:
1) 重定向标准入
exec 6<&0 # 创建标准输入的副本描述符6
exec < FILE # 重定向标准输入为FILE,在此命令之后的所有命令的标准输入都重定向为文件FILE
exec 0<&6 6<&- # 恢复标准输入,关闭描述符6
2) 将指定输入文件的内容转换为大写并输出到指定的输出文件
if [ ! -r $INPUT -o -z $OUTPUT ]; then exit 1; fi
exec 4<&0 # 创建标准输入的副本描述符4
exec < $INPUT # 重定向标准输入为$INPUT
exec 7>&1 # 创建标准输入的副本描述符7
exec < $OUTPUT # 重定向标准输出为$OUTPUT
cat - | tr 'a-z' 'A-Z' # cat -从标准输入读取,tr将转换后的内容输出到标准输出,但标准输入和标准输出分别重定向到两个文件。注cat -可省略
3) 使用重定向避免无法访问子shell变量的i问题
Lines=0
cat FILE | while read line; do
echo $line
((Lines++)) # 管道之后的命令是在子shell中执行的,循环之外(即父shell中)变量Lines将保持不变
done
echo "number of lines: $Lines" # 0
echo "-------------before wrong--------"
exec 3<> FILE
while read line 或 while read line <& 3 # 注意对于文件名不可以使用这种方式,否则会死循环
do do
echo "$line" echo "$line"
((Lines++)) ((Lines++))
done <& 3 done
exec 3<&- exec 3<&-
echo "number of lines: $Lines" # 输出文件中的行数
注:使用文件名描述符会移动文件指针
重定向代码块:
代码块包括while, until, for, if/then的块, here文档以及{}和()代码块,甚至函数都可以重定向。方法就是在代码块末尾加上重定向操作符<或>
eg:
1) while重定向
while [ "$name" != Smith ] # for/until类似
do
read name # 从文件FILE中读取
echo $name
let "count += 1"
done < FILE # 重定向标准输入为FILE
2) 从here document重定向
while read line # 从here document中读取
do
echo $line
let "count++"
done < EOF
$(ls -l)
EOF
3) for重定向标准输入和标准输出
for name in `seq $line_count`
do
read name # 从$INPUT文件中读取
echo "$name"
done < "$INPUT" > "$OUTPUT" # 重定向标准输入到$INPUT,标准输出到$OUTPUT
4) if/then测试块重定向
if :; then
read name # 从$FILE中读取,仅读取$FILE中的第一行
echo $name
fi < "$FILE" # 重定向标准输入为$FILE
5) 函数重定向标准输入和标准输出
file_excerpt()
{
read line # 从文件$FILE中读取
echo "$line" | grep $1 | awk -F":" '{ print $5 }'
} < /etc/passwd # 重定向函数的标准输入到文件/etc/passwd
注意:f(){ cmd1; } | cmd2 不能正确执行,要改为 f() { { cmd1; } | cmd2; }
6) {}重定向标准输入
{
read line1
read line2
} < $File # 从文件$FILE中读取第一行和第二行
7) ()重定向标准输出
(
echo "Archive Description:"
rpm -qpi $1 # Query description.
echo
echo "Archive Listing:"
rpm -qpl $1 # Query listing.
echo
rpm -i --test $1 # Query whether rpm file can be installed.
if [ "$?" -eq $SUCCESS ]; then
echo "$1 can be installed."
else
echo "$1 cannot be installed."
fi
) > "$1.test" # Redirects output of everything in block to file.
8)
mkfifo /tmp/fifo1 /tmp/fifo2
while read a; do echo "FIFO1: $a"; done < /tmp/fifo1 & exec 7> /tmp/fifo1
exec 8> >(while read a; do echo "FD8: $a, to fd7"; done >&7)
exec 3>&1
(
(
(
while read a; do echo "FIFO2: $a"; done < /tmp/fifo2 | tee /dev/stderr \
| tee /dev/fd/4 | tee /dev/fd/5 | tee /dev/fd/6 >&7 & exec 3> /tmp/fifo2
echo 1st, to stdout
sleep 1
echo 2nd, to stderr >&2
sleep 1
echo 3rd, to fd 3 >&3
sleep 1
echo 4th, to fd 4 >&4
sleep 1
echo 5th, to fd 5 >&5
sleep 1
echo 6th, through a pipe | sed 's/.*/PIPE: &, to fd 5/' >&5
sleep 1
echo 7th, to fd 6 >&6
sleep 1
echo 8th, to fd 7 >&7
sleep 1
echo 9th, to fd 8 >&8
) 4>&1 >&3 3>&- | while read a; do echo "FD4: $a"; done 1>&3 5>&- 6>&-
) 5>&1 >&3 | while read a; do echo "FD5: $a"; done 1>&3 6>&-
) 6>&1 >&3 | while read a; do echo "FD6: $a"; done 3>&-
rm -f /tmp/fifo1 /tmp/fifo2