输入和输出
在Linux中一切皆文件,即使是硬件,在Linux系统中同样的表示为文件。有三个标准的POSIX字符,被成为文件描述符。每个Linux命令都会使用到0、1、2三个文件描述符与用户或其他系统程序进行交互。
0——标准输入——键盘:从文件(默认是键盘)读取输入
1——标准输出——屏幕:发送数据到文件(默认为屏幕)
2——标准错误——屏幕:发送所有错误信息到一个文件(默认为屏幕)
标准输入
在Shell运行任何命令之前,都会尝试打开文件进行读取。如果打开文件失败,Shell将以一个错误的退出并不运行命令。如果打开成功,Shell使用打开的文件的文件描述符作为命令的标准输入文件描述符。
标准输入具有如下特点:
它是默认的输入方法,它被所有命令使用来读取输入
它用数字0表示
也被称为stdin
默认的标准输入设备是键盘
操作符"<"是输入重定向操作符,语法:
command < input_file
如:
[root@rs1 io]# cat < 1.txt 狗肉汤就是用狗肉炖的汤
标准输出
标准输出有如下特点:
它被命令用来写入或显示命令自身的输出
它用数字1表示
它也被成为stdout
默认的标准输出设备是屏幕
操作符"<"是输出重定向操作符,语法:
command > out_file
Shell首先尝试打开用于写入的文件out_file,如果成功,就将命令的标准输出发送到打开的文件中;如果打开文件失败,整个命令失败。
command > out_file和command 1>out_file的意义相同
如:
[root@rs1 io]# ls > 2.txt [root@rs1 io]# cat 2.txt 1.txt 2.txt 如果输出文件不存在,系统会自动创建。如果存在,使用">"会被重写
标准错误
标准错误具有如下特点:
它是默认的错误输出方法,被用于写入所有系统错误信息
它用数字2表示
它也被成为stderr
默认的标准错误输出设备是屏幕
操作符"2>"是标准错误重定向操作符,语法:
command 2> error_file
如:
[root@rs1 io]# cajig 2> error_txt [root@rs1 io]# cat error_txt -bash: cajig: command not found 由于cajig命令不存在,系统会提示错误信息,2>将标准错误重定向到了error_txt文件中
重定向
在LInux中,总有三个默认的设备文件是打开的,即stdin、stdout、stderr。这三个文件和其他任何打开的文件都可以被重定向。所谓重定向就是指从文件、命令、程序、脚本,甚至脚本中的代码块获得输出并把它作为输入写入另一个文件、命令、程序或脚本中。
每个打开的文件都对应一个文件描述符(非负整数)。stdin(0)、stdout(1)、stderr(2),所以当打开其他文件时,文件描述符号从3开始。
文件重定向
文件重定向时更改一个文件描述符以指向一个文件。
如:(发送标准错误到一个文件)
[root@rs1 io]# cat stderr_1.sh #如果参数小于1,则提示信息,并退出脚本 if test $# -lt 1 then echo "Usage: $0 DIRECTORY..." exit 1 fi #使用for循环遍历所有参数 for i in $@ do #找到指定目录中以.tmp为后缀的文件,并删除 find $i -name "*.tmp" -exec rm -rf {} \; #将for循环产生的错误写入到文件error.log中 done 2> error.log
注意:在脚本文件中,重定向符并没有在rm命令之后,因为,重定向应用于循环内生成的所有标准错误的输出,Bash在循环开始前就已经打开了error.log文件(如果不存在,先创建),并将标准错误指向它,然后当循环结束时,关闭它。运行在循环内部的所有命令都从Bash继承打开的文件描述符。
">"是标准输出重定向操作符,但是它会覆盖之前定向到文件里的所有内容,">>"则表示将标准输出追加进指定的文件中(不对之前文件内存在的数据进行操作)。
从文件输入
我们有时需要使用一个代码块使用重定向读取文件的内容。
如:
[root@rs1 io]# cat std_1.sh #如果参数个数不为1,则执行if语句 if test $# -ne 1 then #打印脚本使用方法 echo "Usage: $0 FILEPATH..." #退出 exit 1 fi #定义一个变量file,并将脚本执行的第一个参数赋值给file file=$1 #定义一个代码块 { #读取一行内容,并将读取内容存放到变量line1中 read line1 #读取一行内容,并将读取的内容存放到变量line2中 read line2 #将这个代码块的标准输入指向变量file所对应的文件 } < $file #打印变量file的值和一些信息 echo "First line in $file is : " #打印变量line1的值 echo "$line1" #打印变量file的值和一些信息 echo "Second line in $file is : " #打印变量line2的值 echo "$line2" #退出脚本,并且退出状态码为0 exit 0
执行脚本:
[root@rs1 io]# bash std_1.sh //没有添加参数执行结果 Usage: std_1.sh FILEPATH... [root@rs1 io]# bash std_1.sh ./1.txt //添加参数为当前目录下的1.txt文件 First line in ./1.txt is : 狗肉汤就是用狗肉炖的汤 Second line in ./1.txt is : ddif [root@rs1 io]# cat 1.txt //1.txt中的内容 狗肉汤就是用狗肉炖的汤 ddif fdisk zone tty
该脚本使用重定向从指定的文件中读取文件头两行内容。脚本中大括号"{}"之间的代码称之为一个代码块,然后使用"<$"将这个代码块的标准输入指向"$file"中
有时候我们需要逐行读取内容,并对没一行数据进行特殊处理。这时,最好的解决方法就是将循环语句和重定向结合起来使用,读取并处理文件内容。
如:(while循环和重定向组合)
[root@rs1 io]# cat std_2.sh #如果指定给脚本的参数个数不为1,则执行if语句 if test $# -ne 1 then echo "Usage: `basename $0` FILE_PATH..." exit 1 fi #定义变量filename和count,并将脚本的第一个参数赋值给filename变量 filename=$1 count=0 #使用while循环逐行读取内容,并将内容存入变量LINE while read LINE do #count自增,记录读取到多少行 let count++ #输出当前行的信息 echo "the $count Line contxt is:" echo "$LINE" done < $filename #这个重定向将整个while循环的标准输入指向了文件$filename echo "Total $count has been read over" exit 0
执行脚本:
[root@rs1 io]# bash std_2.sh Usage: std_2.sh FILE_PATH... [root@rs1 io]# bash std_2.sh 1.txt the 1 Line contxt is: 狗肉汤就是用狗肉炖的汤 the 2 Line contxt is: ddif the 3 Line contxt is: fdisk the 4 Line contxt is: zone the 5 Line contxt is: tty Total 5 has been read over
如果使用if循环,但是这种方法只会读取文件第一行内容
[root@rs1 io]# cat std_3.sh if test $# -ne 1 then echo "Usage: `basename $0` FILE_PATH..." exit 1 fi filename=$1 count=0 if true then read LINE let count++ echo "The $count contxt is:" echo "$LINE" fi < $filename echo "Total $count has been read over" exit 0
执行脚本:
[root@rs1 io]# bash std_3.sh Usage: std_3.sh FILE_PATH... [root@rs1 io]# bash std_3.sh 1.txt The 1 contxt is: 狗肉汤就是用狗肉炖的汤 Total 1 has been read over
从文本或字符串输入
Bash还有一种重定向的类型是here-documents,这种重定向的操作符是"<<MARKER"。这种操作符指示Bash从标准输入读取输入的内容,直到读取到只包含MARKER的行为止。其语法:
command <<MARKER
HERE DOCUMENTS
MARKER
MARKER可以是任何单词作为标志。
如:
[root@rs1 io]# tr a-z A-Z <<EOF one two three fou five six EOF ONE TWO THREE FOU FIVE SIX
重定向操作符"<<"和边界标示符"EOF"之间不需要空格分割。在"<<"和EOF之间添加"-",将会忽略行首的制表符。这使Shell脚本中缩进的here-documents的值不会改变。
[root@rs1 io]# cat heredoc_1.sh #!/bin/bash #将here-documents中的内容转换为大写 tr a-z A-Z <<EOF one two three Four Five Six EOF #将here-documents中的内容转换为大写,忽略行首制表符 tr a-z A-Z <<-EOF seven eight nine ten EOF
执行脚本:
[root@rs1 io]# bash heredoc_1.sh ONE TWO THREE FOUR FIVE SIX SEVEN EIGHT NINE TEN
默认情况下,Bash替换会再here-documents的内容上执行,即here-documents内部的变量和命令回被执行。如:
[root@rs1 io]# cat <<EOF > Working dir is $PWD > EOF Working dir is /mnt/io
here-string是here-documents的一个变种。它由操作符"<<<"和作为标准输入的字符串构成,here-string是一个用于输入重定向的普通字符串。语法:
command <<<WORD
单个单词不需要引号引用,中间如果有空格的字符串,则需要引号引用起来。
如:
[root@rs1 io]# tr a-z A-Z <<<one ONE [root@rs1 io]# tr a-z A-Z <<<"one two" ONE TWO [root@rs1 io]# tr a-z A-Z <<<one two tr: extra operand ‘two’ Try 'tr --help' for more information.
空文件创建
创建空文件的语法:
> filename
操作符">"重定向输出到一个文件。如果没有命令指定并且文件不存在的话,Bash将会创建一个空文件。
如:
[root@rs1 io]# cat empty_file.sh #定义变量tarcmd tarcmd=/bin/tar #存储路径 store=/store #需要备份的目录名 backdirs="/var/www/html /mnt" #日志文件的名字 errlog=/tmp/tarbackup.error #当前日期 today=`date +%Y%m%d` #删除就得日志文件并创建新的空文件 >$errlog #使用tar命令将需要备份的目录备份到指定目录里面,并将错误输出重定向到errlog所指向的文件 $tarcmd -cvf $store/$today.tar $backdirs 2>$errlog
执行脚本:
[root@rs1 io]# bash empty_file.sh [root@rs1 io]# ls /store/ 20180710.tar [root@rs1 io]# ls error.log error.log
>$errlog在每次运行tar之前,先清空之前的日志文件内容
丢掉不需要的输出
写入到/dev/null的所有数据都被系统丢弃。所以可以将任何不需要的程序或者命令的输出发送到/dev/null中。
如:
当我们在/etc/passwd中搜索用户root时,只是想得到找到或者没有找到的信息。
[root@rs1 io]# grep "^root" /etc/passwd && echo "user \"root\" was found" || echo "user \"root\" does not exits" root:x:0:0:root:/root:/bin/bash user "root" was found //这中方式,直接显示了root的相关信息,我们不需要回显root信息,可以将这段显示扔进/dev/null中 [root@rs1 io]# grep "^root" /etc/passwd > /dev/null && echo "user \"root\" was found" || echo "user \"root\" does not exits" user "root" was found
标准错误重定向
command 2> error.log
标准输出重定向
command 1> output_file command > output_file
标准输出、错误同时重定向
command &> file commadn >& file command > file 2>&1 command 2>&1 > file
如:
[root@rs1 io]# bash -x empty_file.sh &> debug.log [root@rs1 io]# cat debug.log + tarcmd=/bin/tar + store=/store + backdirs='/var/www/html /mnt' + errlog=/tmp/tarbackup.error ++ date +%Y%m%d + today=20180710 + /bin/tar -cf /store/20180710.tar /var/www/html /mnt
当我们在编译某个安装包时,可以使用如下命令:
(./configure && make && make install) > /tmp/make.log 2&>1
或者:
(./configure && make && make install) 2>&1 /tmp/make.log
追加重定向输出
符号">>"用于追加重定向输出。语法:
command >> filename
在单命令行进行标准输入输出重定向
可以在一条命令行中完成标准输入输出重定向。语法:
command < input_file >output_file
或:
< input_file command > outout_file
如:(我们需要将一个文件中所有内容转化为大写,并重写到一个新的文件中)
[root@rs1 io]# cat 1.txt 狗肉汤就是用狗肉炖的汤 ddif fdisk zone tty [root@rs1 io]# tr a-z A-Z < 1.txt > new_file [root@rs1 io]# cat new_file 狗肉汤就是用狗肉炖的汤 DDIF FDISK ZONE TTY
这里有一个例子,再一个命令中进行标准输入输出重定向,用于解包一个rpm归档文件:
[root@rs1 derpm]# cat derpm.sh #如果指定给脚本的参数个数不为1,则执行if语句 if test $# -ne 1 then echo "Usage: `basename $0` target_file" exit 1 fi #定义变量TEMPFILE,并指定一个唯一的临时文件名作为变量的值 TEMPFILE=/tmp/$$.cpio #使用rpm2cpio命令,将脚本的第一个参数所代表的rpm归档文件转换为变量TEMPFILE所代表的cpio归档文件 rpm2cpio < $1 > $TEMPFILE #使用cpio命令,将TEMPFILE所代表的cpio归档文件进行解包 cpio --make-directories -F $TEMPFILE -i #删除cpio归档文件 rm -f $TEMPFILE #退出脚本,且退出状态码为0 exit 0
执行脚本:
[root@rs1 derpm]# bash derpm.sh Usage: derpm.sh target_file [root@rs1 derpm]# bash derpm.sh httpd-2.4.6-45.el7.x86_64.rpm 7703 blocks [root@rs1 derpm]# ls derpm.sh etc httpd-2.4.6-45.el7.x86_64.rpm run usr var
使用rpm2cpio命令先将指定的rpm归档文件转换为cpio归档文件,再使用cpio命令进行解包。
文件描述符
Shell有时会引用使用文件描述符(fd)的文件。我们一般使用文件描述符的范围是0~9。重定向大于9的文件描述符要谨慎,因为它们可能于Shell内部使用的文件描述符冲突。
使用exec命令
Bash的内部命令exec的功能之一就是允许操作文件描述符。如果再exec后没有指定命令,则exec命令之后的重定向将更改当前Shell的文件描述符号。
如:
[root@rs1 exec]# cat exec_1.sh #如果没有指定参数,则执行if语句 if [[ $# -eq 0 ]] then echo "Usage: `basename $0` filename..." exit 1 fi #将指定给脚本的第一个参数赋值给变量file file=$1 #逐行读取文件内容,并将读取的数据存入变量line中 while read -r line do echo $line #等待用户键入任意键 read -p "Press any key to continue." -n 1 done < $file #将while循环的标准输入指向变量file所代表的文件
执行脚本:
[root@rs1 exec]# cat 1.txt line 1 狗肉汤 line 2 爱国者 line 3 coco line 4 FSX [root@rs1 exec]# bash exec_1.sh 1.txt line 1 狗肉汤 ine 2 爱国者 ine 3 coco ine 4 FSX [root@rs1 exec]# bash exec_1.sh Usage: exec_1.sh filename...
执行过程中"read -p "Press any key to continue." -n 1"这句命令并没有被执行。因为我们将1.txt作为输入重定向到while循环中,while循环中所有的命令都继承了这个文件描述符,因此read将重定向后的标准输入,而不再将键盘作为标准输入。
所以,因该做如下修改:
[root@rs1 exec]# cat exec_2.sh #如果没有指定参数,则执行if语句 if [[ $# -eq 0 ]] then echo "Usage: `basename $0` filename..." exit 1 fi #将脚本的第一个参数作为输入文件,并指定其文件描述符为3 exec 3< $1 #逐行读取文件内容,并将读取的数据存入变量line中 while read -u 3 line do echo $line #等待用户键入任意键 read -p "Press any key to continue." -n 1 done exec 3<&-
执行脚本:
[root@rs1 exec]# bash exec_2.sh Usage: exec_2.sh filename... [root@rs1 exec]# bash exec_2.sh 1.txt line 1 狗肉汤 Press any key to continue. line 2 爱国者 Press any key to continue. line 3 coco Press any key to continue. line 4 FSX Press any key to continue. Press any key to continue.
再脚本里面使用了"read -u 3 line",其含义:-u选项可以指定从特定的文件描述符中读取数据,3标示读取文件描述符为3的文件。这对于逐行地读取文件内容或者依次读取一个单词很有用。
指定用于输入的文件描述符
Shell允许给一个输入文件或输出文件指定一个文件描述符。这样可以提高文件读写的性能。这类文件描述符被成为用户自定义文件描述符。语法:
exec [n]<file
[n]就是指定的文件描述符,如果不指定n,这使用stdin(0)。上述的输入重定向再文件描述符n上打开一个用于读取的文件file。
如:
[root@rs1 exec]# cat exec_3.sh #如果没有指定参数,则执行if语句 if [[ $# -eq 0 ]] then echo "Usage: `basename $0` filename..." exit 1 fi #将脚本的第一个参数作为输入文件,并指定一个文件描述符3 exec 3< $1 #将标准输入作为文件描述符3的副本 cat <& 3 #关闭文件描述符号3 exec 3<&-
执行脚本:
[root@rs1 exec]# bash -x exec_3.sh 1.txt + [[ 1 -eq 0 ]] + exec + cat line 1 狗肉汤 line 2 爱国者 line 3 coco line 4 FSX + exec [root@rs1 exec]# bash -x exec_3.sh + [[ 0 -eq 0 ]] ++ basename exec_3.sh + echo 'Usage: exec_3.sh filename...' Usage: exec_3.sh filename... + exit 1
再通过一个例子,进一步了解exec命令用于输入的文件描述符:
[root@rs1 exec]# cat exec_4.sh #将标准输入赋值到文件描述符6,保存标准输入 exec 6<&0 #将文件/etc/hosts重定向到标准输入 exec < /etc/hosts #读取文件/etc/hosts文件第一行,并将数据保存到变量line1中 read line1 #读取文件/etc/hosts文件第二行,并将数据保存到变量line2中 read line2 cat <<-EOF Following lines read form file ------------------------------ first line contxt: `echo $line1` second line contxt: `echo $line2` EOF #从文件描述符6中恢复标准输入,并关闭文件描述符6 exec <&6 6<&- echo -n "Enter data :" #现在,read命令从标准输入中读取数据,并赋值给Line1 read Line1 cat <<-EOF Innput read form stdin ---------------------- `echo "stdin input :" $Line1` EOF
执行脚本:
[root@rs1 exec]# bash exec_4.sh Following lines read form file ------------------------------ first line contxt: 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 second line contxt: ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 Enter data :fsx123 //此处需要使用键盘键入数据,因为此是键盘已经成为了命令继承的输入 Innput read form stdin ---------------------- stdin input : fsx123
指定用于输出的文件描述符
给一个输出文件指定一个文件描述符的语法:
exec [n]>file
其中,[n]就是文件描述符,如果不指定,则默认为1,即stdout。
上述的语法,再输出重定向时,会在文件描述符n上打开一个file,用于保存输出。如果文件不存在,系统会创建,如果已经存在,则回被清0。
如:
[root@rs1 exec]# exec 4>file //将标准输出重定向到文件描述符为4的发ile文件中 [root@rs1 exec]# date >& 4 //执行结果复制到文件描述符4 [root@rs1 exec]# cat file Wed Jul 11 00:40:16 CST 2018
这里的">&"不时标准输入输出时用于重定向的操作符,它提供了复制输出文件描述符的能力。语法:
[n] >& n
如果n没有指定,则默认使用stdout。如果数字n指定的文件描述符没有被打开用于输出,会发生重定向错误。
[root@rs1 exec]# date >& 3 date: write error: Bad file descriptor
这里有一个脚本来进一步理解输出文件描述符:
[root@rs1 exec]# cat exec_5.sh #定义变量LOGFILE并赋值 LOGFILE=./logfile.txt #复制文件描述符6到标准输出 exec 6>&1 #重定向标准输出到变量LOGFILE所代表的文件中 exec > $LOGFILE #之后在关闭文件描述符6之前,所有的输出都被重写到LOGFILE中 echo -n "Logfile:" echo echo "date command" date echo "------------------" echo "Output of \"uname -r \" command" uname -r echo "------------------" echo "Outpuf of \"df\" command" df -h #恢复标准输出并关闭文件描述符6 exec 1>&6 6>&- echo "==stdout now restored to default==" ifconfig eth0 #退出脚本,并且退出码为0 exit 0
执行脚本:
[root@rs1 exec]# bash exec_5.sh ==stdout now restored to default== eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.25.254.15 netmask 255.255.0.0 broadcast 172.25.255.255 inet6 fe80::5054:ff:feb1:f80 prefixlen 64 scopeid 0x20<link> ether 52:54:00:b1:0f:80 txqueuelen 1000 (Ethernet) RX packets 111804 bytes 11287583 (10.7 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 65803 bytes 10698124 (10.2 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 [root@rs1 exec]# cat logfile.txt Logfile: date command Wed Jul 11 00:54:51 CST 2018 ------------------ Output of "uname -r " command 3.10.0-123.el7.x86_64 ------------------ Outpuf of "df" command Filesystem Size Used Avail Use% Mounted on /dev/mapper/rhel-root 4.9G 919M 4.0G 19% / devtmpfs 239M 4.0K 239M 1% /dev tmpfs 246M 0 246M 0% /dev/shm tmpfs 246M 8.4M 237M 4% /run tmpfs 246M 0 246M 0% /sys/fs/cgroup /dev/vda1 497M 97M 401M 20% /boot
一个实战脚本,深化执行命令并将命令的结果发送到指定的文件描述符:
[root@rs1 test]# cat exec.sh #定义变量NOW,值为当前日期。格式:yyyymmdd NOW=`date +%Y%m%d` #定义变量OUTPUT OUTPUT=./output.txt exec 3>&1 #在文件描述符3上打开变量OUTPUT文件,用于写入 exec >$OUTPUT echo "The Information $NOW collect as:" cat <<EOF --------------------------------- System Info run @ $(date) for $(hostname) --------------------------------- EOF cat <<-EOF ******************************** ******Installed Hard Disk******* ******************************** EOF #显示系统中已经安装的磁盘 fdisk -l |egrep "^Disk /dev" echo ---------------------------------------------- echo cat <<-EOF ******************************** **File System Disk Space Usage** ******************************** EOF #显示文件系统磁盘使用情况 df -H echo ---------------------------------------------- echo cat <<-EOF ******************************** ********Cpu Information********* ******************************** EOF #显示cpu类型 grep 'model name' /proc/cpuinfo | uniq | awk -F: '{ print $2 }' echo ---------------------------------------------- echo cat <<-EOF ******************************** *****Operating System Info****** ******************************** EOF #显示系统信息 uname -a echo ---------------------------------------------- echo release=/usr/bin/lsb_release #如果文件/usr/bin/lsb_release存在并且可执行,则打印系统发行版本所有信息,否则提示文件不存在 [ -x $release ] && $release -a || echo " file $release does not exist!" cat <<-EOF ******************************** *Amount Of Free And Used Memory* ******************************** EOF #显示剩余内存和使用的内存 free -m echo ---------------------------------------------- echo cat <<-EOF ******************************** **Top 10 Memory Eating Process** ******************************** EOF #显示最消耗内存的10个进程 ps -auxf | sort -nr -k 4 | head -10 echo ---------------------------------------------- echo cat <<-EOF ******************************** ***Top 10 CPU Eating Process**** ******************************** EOF #显示最消耗cpu的10个进程 ps -auxf | sort -nr -k 3 |head -10 echo ---------------------------------------------- echo cat <<-EOF ************************************* **Network Device Information [eth0]** ************************************* EOF #显示第一块网卡的信息 netstat -i | grep -q eth0 && ifconfig eth0 || echo "eth0 is not installed" echo ---------------------------------------------- echo cat <<-EOF ************************************* *******Wireless Devicce [wlan0]****** ************************************* EOF #显示无限网咖信息,如果不存在提示 netstat -i | grep -q wlan0 && ifconfig wlan0 || echo "wlan0 is not installed" echo ---------------------------------------------- echo cat <<-EOF ************************************* *****All Network Interfaces Stats**** ************************************* EOF #显示所有网卡的状态 netstat -i echo ---------------------------------------------- echo exec 1>&3 3>&- echo "System info wrote to $OUTPUT file"
执行脚本:
[root@rs1 test]# bash exec.sh System info wrote to ./output.txt file
输出内容几乎都被重定向到文件描述符打开的output.txt文件中,内容如下:
[root@rs1 test]# cat output.txt The Information 20180711 collect as: --------------------------------- System Info run @ Wed Jul 11 01:47:10 CST 2018 for rs1 --------------------------------- ******************************** ******Installed Hard Disk******* ******************************** Disk /dev/vda: 6442 MB, 6442450944 bytes, 12582912 sectors Disk /dev/mapper/rhel-root: 5268 MB, 5268045824 bytes, 10289152 sectors Disk /dev/mapper/rhel-swap: 645 MB, 645922816 bytes, 1261568 sectors ---------------------------------------------- ******************************** **File System Disk Space Usage** ******************************** Filesystem Size Used Avail Use% Mounted on /dev/mapper/rhel-root 5.3G 964M 4.3G 19% / devtmpfs 251M 4.1k 251M 1% /dev tmpfs 257M 0 257M 0% /dev/shm tmpfs 257M 8.8M 249M 4% /run tmpfs 257M 0 257M 0% /sys/fs/cgroup /dev/vda1 521M 101M 420M 20% /boot ---------------------------------------------- ******************************** ********Cpu Information********* ******************************** Intel Xeon E312xx (Sandy Bridge) ---------------------------------------------- ******************************** *****Operating System Info****** ******************************** Linux rs1 3.10.0-123.el7.x86_64 #1 SMP Mon May 5 11:16:57 EDT 2014 x86_64 x86_64 x86_64 GNU/Linux ---------------------------------------------- file /usr/bin/lsb_release does not exist! ******************************** *Amount Of Free And Used Memory* ******************************** total used free shared buffers cached Mem: 490 200 289 8 0 85 -/+ buffers/cache: 114 375 Swap: 615 0 615 ---------------------------------------------- ******************************** **Top 10 Memory Eating Process** ******************************** root 568 0.0 3.2 549976 16068 ? Ssl Jul05 0:50 /usr/bin/python -Es /usr/sbin/tuned -l -P root 561 0.0 1.7 377920 8684 ? Ssl Jul05 0:01 /usr/sbin/NetworkManager --no-daemon polkitd 615 0.0 1.4 513848 7496 ? Ssl Jul05 0:00 /usr/lib/polkit-1/polkitd --no-debug root 7762 0.0 0.9 131524 4840 ? Ss Jul10 0:01 \_ sshd: root@pts/0 root 5608 0.0 0.9 131524 4836 ? Ss Jul08 0:00 \_ sshd: root@pts/1 root 828 0.0 0.7 82956 3608 ? Ss Jul05 0:00 /usr/sbin/sshd -D root 1 0.0 0.7 47480 3728 ? Ss Jul05 0:00 /usr/lib/systemd/systemd --switched-root --system --deserialize 23 postfix 8068 0.0 0.7 91804 3904 ? S 01:22 0:00 \_ pickup -l -t unix -u postfix 1806 0.0 0.7 91872 3924 ? S Jul05 0:00 \_ qmgr -l -t unix -u root 7798 0.0 0.4 115452 2144 pts/0 S+ Jul10 0:00 \_ bash ---------------------------------------------- ******************************** ***Top 10 CPU Eating Process**** ******************************** USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 910 0.0 0.1 113280 744 ? Ss Jul05 0:00 /usr/bin/rhsmcertd root 9 0.0 0.0 0 0 ? S Jul05 0:00 \_ [rcuob/0] root 8375 0.0 0.1 107900 664 pts/1 S+ 01:47 0:00 | \_ head -10 root 8374 0.0 0.0 113120 204 pts/1 R+ 01:47 0:00 | \_ bash exec.sh root 8373 0.0 0.2 123512 1436 pts/1 R+ 01:47 0:00 | \_ ps -auxf root 8350 0.0 0.2 113120 1464 pts/1 S+ 01:47 0:00 | \_ bash exec.sh root 828 0.0 0.7 82956 3608 ? Ss Jul05 0:00 /usr/sbin/sshd -D root 8228 0.0 0.0 0 0 ? S 01:43 0:00 \_ [kworker/0:2] root 81 0.0 0.0 0 0 ? S Jul05 0:00 \_ [kauditd] ---------------------------------------------- ************************************* **Network Device Information [eth0]** ************************************* eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.25.254.15 netmask 255.255.0.0 broadcast 172.25.255.255 inet6 fe80::5054:ff:feb1:f80 prefixlen 64 scopeid 0x20<link> ether 52:54:00:b1:0f:80 txqueuelen 1000 (Ethernet) RX packets 119843 bytes 12033485 (11.4 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 70920 bytes 11532462 (10.9 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ---------------------------------------------- ************************************* *******Wireless Devicce [wlan0]****** ************************************* wlan0 is not installed ---------------------------------------------- ************************************* *****All Network Interfaces Stats**** ************************************* Kernel Interface table Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg eth0 1500 119843 0 0 0 70920 0 0 0 BMRU lo 65536 0 0 0 0 0 0 0 0 LRU ----------------------------------------------
关闭文件描述符
在之前已经反复使用了这个操作。语法:
[n] <&- //关闭标准输入
或者
[n] >&- //关闭文件描述符,如果n=2就是关闭标准错误
主动关闭手动打开的文件描述符是一个好习惯。
打开用于读写的文件描述符
Bash支持使用如下语法在文件描述符上打开一个可读写的文件:
exec [n]<>file
其中n是文件描述符,如果不指定则默认标准输入。如果文件file不存在,则先创建。符号"<>"称为菱形操作符,标示打开一个可读写的文件。
这个语法对更新文件很有用。
如:
#将字符串"one two"写入到文件file1中 [root@rs1 test]# echo "one two" > file1 #在文件描述符4上打开文件file1 [root@rs1 test]# exec 4<> file1 #从文件描述符4上读取前5个字节 [root@rs1 test]# read -n 5 var <& 4 [root@rs1 test]# echo $var one t
可以看到,var保存了最开始写入内容的前5个字节,然后想文件描述符里写入数据
[root@rs1 test]# echo -n + >& 4 [root@rs1 test]# exec 4>&- [root@rs1 test]# cat file1 one t+o
我们可以看到,结果是"one t+o",而不是"one two+"。值和是因为,我们先用read读取了前5个字节,而操作符"<>"会使后续的读写操作跟随先前读写操作的位置(就是说文件指针没有在最后面,二是停留在该生命周期内,最后一次读写到的位置),所以+会被写在地6个字符位置。