exec <filename 命令重定向stdin到一个文件。从那时起,所有stdin都来自该文件,而不是其正常来源(通常是键盘输入)。这提供了一种逐行读取文件的方法,并可能使用 sed 和/或 awk 解析每行输入。
示例 20-1. 重定向stdin使用 exec
#!/bin/bash # Redirecting stdin using 'exec'. exec 6<&0 # Link file descriptor #6 with stdin. # Saves stdin. exec < data-file # stdin replaced by file "data-file" read a1 # Reads first line of file "data-file". read a2 # Reads second line of file "data-file." echo echo "Following lines read from file." echo "-------------------------------" echo $a1 echo $a2 echo; echo; echo exec 0<&6 6<&- # Now restore stdin from fd #6, where it had been saved, #+ and close fd #6 ( 6<&- ) to free it for other processes to use. # # <&6 6<&- also works. echo -n "Enter data " read b1 # Now "read" functions as expected, reading from normal stdin. echo "Input read from stdin." echo "----------------------" echo "b1 = $b1" echo exit 0 |
类似地,exec >filename 命令重定向stdout到一个指定的文件。这会将通常发送到stdout的所有命令输出发送到该文件。
![]() | exec N > filename 影响整个脚本或当前 shell。从那时起,脚本或 shell 的 PID 中的重定向已更改。然而 . . . N > filename 仅影响新 fork 的进程,而不影响整个脚本或 shell。 感谢 Ahmed Darwish 指出这一点。 |
示例 20-2. 重定向stdout使用 exec
#!/bin/bash # reassign-stdout.sh LOGFILE=logfile.txt exec 6>&1 # Link file descriptor #6 with stdout. # Saves stdout. exec > $LOGFILE # stdout replaced with file "logfile.txt". # ----------------------------------------------------------- # # All output from commands in this block sent to file $LOGFILE. echo -n "Logfile: " date echo "-------------------------------------" echo echo "Output of \"ls -al\" command" echo ls -al echo; echo echo "Output of \"df\" command" echo df # ----------------------------------------------------------- # exec 1>&6 6>&- # Restore stdout and close file descriptor #6. echo echo "== stdout now restored to default == " echo ls -al echo exit 0 |
示例 20-3. 同时重定向stdin和stdout在同一脚本中使用 exec
#!/bin/bash # upperconv.sh # Converts a specified input file to uppercase. E_FILE_ACCESS=70 E_WRONG_ARGS=71 if [ ! -r "$1" ] # Is specified input file readable? then echo "Can't read from input file!" echo "Usage: $0 input-file output-file" exit $E_FILE_ACCESS fi # Will exit with same error #+ even if input file ($1) not specified (why?). if [ -z "$2" ] then echo "Need to specify output file." echo "Usage: $0 input-file output-file" exit $E_WRONG_ARGS fi exec 4<&0 exec < $1 # Will read from input file. exec 7>&1 exec > $2 # Will write to output file. # Assumes output file writable (add check?). # ----------------------------------------------- cat - | tr a-z A-Z # Uppercase conversion. # ^^^^^ # Reads from stdin. # ^^^^^^^^^^ # Writes to stdout. # However, both stdin and stdout were redirected. # Note that the 'cat' can be omitted. # ----------------------------------------------- exec 1>&7 7>&- # Restore stout. exec 0<&4 4<&- # Restore stdin. # After restoration, the following line prints to stdout as expected. echo "File \"$1\" written to \"$2\" as uppercase conversion." exit 0 |
I/O 重定向是避免可怕的 子 shell 中不可访问的变量 问题的巧妙方法。
示例 20-4. 避免子 shell
#!/bin/bash # avoid-subshell.sh # Suggested by Matthew Walker. Lines=0 echo cat myfile.txt | while read line; do { echo $line (( Lines++ )); # Incremented values of this variable #+ inaccessible outside loop. # Subshell problem. } done echo "Number of lines read = $Lines" # 0 # Wrong! echo "------------------------" exec 3<> myfile.txt while read line <&3 do { echo "$line" (( Lines++ )); # Incremented values of this variable #+ accessible outside loop. # No subshell, no problem. } done exec 3>&- echo "Number of lines read = $Lines" # 8 echo exit 0 # Lines below not seen by script. $ cat myfile.txt Line 1. Line 2. Line 3. Line 4. Line 5. Line 6. Line 7. Line 8. |