Bash : IO 重定向_玖富娱乐主管发布


玖富娱乐是一家为代理招商,直属主管信息发布为主的资讯网站,同时也兼顾玖富娱乐代理注册登录地址。

规范输入/输出(standard I/O)多是软件设计准绳里最主要的观点了。这个观点就是:递次应该有数据的泉源端、数据的目标端(输出效果的处所)已申报题目的处所,它们离别被称为规范输入(standard input)规范输出(standard output)规范毛病输出(standard error)。递次没必要晓得也不消体贴它的输入与输出背地是什么装备,当递次运转时,这些规范 IO 就已翻开并准备就绪了。

运转时的递次称为历程,在 Linux 体系中,关于每一个历程来讲,一直有 3 个"文件"处于翻开状况:

  • stdin
  • stdout
  • stderr

这三个文件就是历程默许的规范输入、规范输出和规范毛病输出。每一个翻开的文件都会被分派一个文件描述符。stdin,stdout 和 stderr 的文件描述符离别是 0,1 和 2(一个文件描述符说白了就是文件体系为了跟踪这个翻开的文件而分派给它的一个数字)。关于 Bash 历程来讲,stdin 默许就是键盘,stdout 和 stderr 默许都是屏幕。

我们能够把 IO 重定向简朴明白为:
体系捕获一个文件、敕令、递次或剧本的输出,然后将这些输出作为输入发送到另一个文件、敕令、递次或剧本中。

IO 重定向的基础观点

把规范输出重定向到文件
> 和 >> 标记把规范输出重定向到文件中
> 会覆盖掉已存在的文件中的内容
>> 则把新的内容追加到已存在的文件中的内容的尾部

好比下面的敕令将会把文件 log.txt 变成一个空文件(就是 size 为 0):

$ : > log.txt

下面的敕令则把 ls 敕令输出的效果追加到 log.txt 文件的尾部:

$ ls >> log.txt 

实在这是省略了规范输出的文件描述符 1 的写法,完整的写法为:

$ ls 1>log.txt

把规范毛病输出重定向到文件
规范毛病的文件描述符为 2,以是重定向规范毛病到文件的写法为:

$ ls 2>error.txt

若是想同时把规范输出和规范毛病输出重定向到同一个文件中,能够运用下面的要领:

$ ls &>log.txt

另有别的一种写法为:

$ ls >log.txt 2>&1

重定向到另一个文件描述符
好比经由历程这类体式格局把规范输出和规范毛病输出重定向到同一个文件中:

$ ls >log.txt 2>&1

注重:& 标记背面跟的是文件描述符而不是文件。

总结一下,我们也许能够获得下面两条划定规矩:
M>N
# "M" 是一个文件描述符,若是没有明白指定的话默许为 1。
# "N" 是一个文件名。
# 文件描述符 "M" 被重定向到文件 "N"。

M>&N
# "M" 是一个文件描述符,若是没有明白指定的话默许为 1。
# "N" 是另一个文件描述符。

封闭文件描述符
文件描述符是能够封闭的,典范的写法有下面几种:
n<&-             # 封闭输入文件描述符 n
0<&-, <&-    # 封闭 stdin
n>&-             # 封闭输出文件描述符 n
1>&-, >&-    # 封闭 stdout

>/dev/null 2>&1 和 2>&1 >/dev/null

Linux 体系中有一个特别的装备文件 /dev/null,发送给它的任何内容都会被抛弃,因而若是须要抛弃规范输出和规范毛病输出的内容时能够运用下面的要领:
1>/dev/null 2>/dev/null
下面的写法与上面的写法是同等的,接下来我们重点来诠释下面的写法:
>/dev/null 2>&1

>/dev/null
>/dev/null 的作用是将规范输出 1 重定向到 /dev/null 中,因而规范输出中的内容被完整抛弃了。

2>&1
2>&1 用到了重定向绑定,接纳 & 能够将两个输出绑定在一起,也就是说毛病输出将会和规范输出输出到同一个处所。

-玖富娱乐是一家为代理招商,直属主管信息发布为主的资讯网站,同时也兼顾玖富娱乐代理注册登录地址。-

实在 Linux 在实行 shell 敕令之前,就会确定好一切的输入输出地位,诠释递次为从左到右顺次实行重定向操纵。以是 >/dev/null 2>&1 的作用就是让规范输出重定向到 /dev/null 中,接下来因为毛病输出的文件描述符 2 被重定向绑定到了规范输出的描述符 1,以是毛病输出也被定向到了 /dev/null 中,毛病输出一样也被抛弃了。

2>&1 >/dev/null
2>&1 >/dev/null 实行的效果和 >/dev/null 2>&1 是不一样的!它的实行历程为:

  1. 2>&1,将毛病输出绑定到规范输出上。因为此时的规范输出是默许值,也就是输出到屏幕,以是毛病输出会输出到屏幕。
  2. >/dev/null,将规范输出1重定向到 /dev/null 中。

exec 与重定向

exec <filename 敕令会将 stdin 重定向到文件中。 从这句最先, 一切的 stdin 就都来自于这个文件了, 而不是规范输入(一般都是键盘输入)。 如许就供应了一种按行读取文件的要领。固然,也能够用这类要领来重定向规范输出和规范毛病输出。下面的 upper.sh 递次把输入文件中的字母转换为大写并输出到别的一个文件中,剧本中运用 exec 同时重定向了 stdin 和 stdout:

#!/bin/bash

E_FILE_ACCESS=70
E_WRONG_ARGS=71

if [ ! -r "$1" ] # 推断指定的输入文件是不是可读
then
    echo "Can't read from input file!"
    echo "Usage: $0 input-file output-file"
    exit $E_FILE_ACCESS
fi #  纵然输入文件($1)没被指定

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 # 生存默许 stdin
exec < $1 # 将会从输入文件中读取.

exec 7>&1 # 生存默许 stdout
exec > $2 # 将写到输出文件中.
# 假定输出文件是可写的

# -----------------------------------------------
cat - | tr a-z A-Z # 转换为大写
# 从 stdin 中读取
# 写到 stdout 上
# 然则,stdin 和 stdout 都被重定向了
# -----------------------------------------------
exec 1>&7 7>&- # 规复 stout
exec 0<&4 4<&- # 规复 stdin

# 规复以后,下边这行代码将会如预期的一样打印到 stdout 上
echo "File "$1" written to "$2" as uppercase conversion."
exit 0

在 upper.sh 递次地点的目录下建立 in.txt 和 out.txt 文件,编纂 in.txt 文件的内容为:

abcd
xxyy

然后运转 upper.sh 递次:

$ ./upper.sh in.txt out.txt

实在另有一种轻微简朴一些的体式格局把规范输入和规范输出重定向到文件:
[j]<>myfile
# 为了读写 myfile,把文件 myfile 翻开, 而且将文件描述符 j 分派给它。
# 若是文件 myfile 不存在, 那末就建立它。
# 若是文件描述符 j 没指定,那默许是 fd 0,即规范输入。
这类运用一般是为了把内容写到一个文件中指定的处所,好比下面的 demo:

echo 1234567890 > myfile # 写字符串到 myfile
exec 6<> myfile          # 翻开 myfile 而且将 fd 6 分派给它
read -n 4 <&6            # 只读取4个字符
echo -n . >&6            # 写一个小数点
exec 6>&-                # 封闭 fd 6
cat myfile               # ==> 1234.67890

制止子 shell
默许情况下,不能在子 shell 中转变父 shell 中变量的值。下面的 demo 经由历程 exec 重定向 IO 有用的规避了子 shell 题目:

#!/bin/bash

E_WRONG_ARGS=71
if [ -z "$1" ]
then
    echo "Usage: $0 input-file"
    exit $E_WRONG_ARGS
fi

Lines=0

cat "$1" | while read line; # 管道会产生子 shell
do {
    echo $line
    (( Lines   )); #  增添这个变量的值
    # 然则外部轮回却不能接见
}
done

echo "Number of lines read = $Lines" # 0
# 毛病!
echo "------------------------"
exec 3<> "$1"
while read line <&3
do {
    echo "$line"
    (( Lines   )); #  增添这个变量的值
    # 如今外部轮回就能够接见了
    #  没有子shell, 如今就没题目了
}
done
exec 3>&-
echo "Number of lines read = $Lines"
exit 0

把上面的代码生存到 avoid-subshell.sh 文件中,然后运转下面的敕令:

$ ./avoid-subshell.sh in.txt

运用重定向 IO 的体式格局获得了准确的效果。

代码块重定向

像 while、until、for 和 if/then 等代码块也是能够举行 IO 重定向的,下面的 demo 把 while 轮回的规范输入重定向到一个文件:

#!/bin/bash

E_WRONG_ARGS=71
if [ -z "$1" ]
then
    echo "Usage: $0 input-file"
    exit $E_WRONG_ARGS
fi

count=0

while [ "$name" != xxyy ]
do
    read name
    if [ -z "$name" ]; then
        break
    fi
    echo $name
    let "count  = 1"
done <"$1"
echo "$count names read"
exit 0

把上面的代码生存到文件 whileblock.sh 中,然后实行下面的敕令,能够看到规范输入重定向后的效果:

$ ./whileblock.sh in.txt

下面的 demo 则同时重定向了 for 轮回的规范输入和规范输出:

#!/bin/bash

E_WRONG_ARGS=71
if [ -z "$1" ]
then
    echo "Usage: $0 input-file output-file"
    exit $E_WRONG_ARGS
fi

if [ -z "$2" ]
then
    echo "Usage: $0 input-file output-file"
    exit $E_WRONG_ARGS
fi

FinalName="xxyy"
line_count=$(wc "$1" | awk '{ print $1 }')

for name in $(seq $line_count)
do
    read name
    echo "$name"
    if [ "$name" = "$FinalName" ]
    then
        break
    fi
done < "$1" > "$2"
exit 0

把上面的代码生存到文件 forblock.sh 中,然后实行下面的敕令,终端上没有任何输出,因为输出都被重定向到了 out.txt 文件:

$ ./forblock.sh in.txt out.txt

总结

在浩瀚的场景中,IO 重定向的效果是不言而喻的。但在一些特别的用例中效果就不是那末显着了,须要我们明白重定向的基础划定规矩,能力明白哪些特别写法的寄义或是写出我们本身惬意的剧本。

参考:
《高等 Bash 剧本编程》
shell 中的>/dev/null 2>&1 是什么鬼?

-玖富娱乐是一家为代理招商,直属主管信息发布为主的资讯网站,同时也兼顾玖富娱乐代理注册登录地址。