20170805bash学习

bash学习

参考

Linux bash总结(一) 基础部分(适合初学者学习和非初学者参考)
Linux 入门公开课
C语言中文网-Shell教程
处理linux的echo命令不输出转义符号的问题
runoob-Shell 教程
Linux标准输入/输出和重定向
Linux 输入输出重定向, &>file, 2>&1, 1>&2 等
exec的重定向 - GitHub
linux shell 管道命令(pipe)使用及与shell重定向区别

数据类型

1.数值

2.字符串

字符串可以用单引号,也可以用双引号,也可以不用引号。单双引号的区别跟PHP类似

2.1单引号

单引号的特点:

  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
  • 单引号字串中不能出现单引号(对单引号使用转义符后也不行
[chen@localhost tmp]$ echo 'hello$val'
hello$val

2.2双引号

双引号的优点:

  • 双引号里可以有变量
  • 双引号里可以出现转义字符
[chen@localhost tmp]$ echo "${val}hello\'"
1hello\'

字符串更多操作,见下面的 运算/2字符串运算

变量&数组

1.变量

1.1定义,使用

  • 变量的定义不加$
  • 不加$表示变量本身,可以val++,加$表示变量存储的值val=$val+1
  • val=anything 等号两侧不能有空格
ubuntu@VM-10-194-ubuntu:/tmp$ VAR="some"
ubuntu@VM-10-194-ubuntu:/tmp$ NUM=123
# 注意:等号两侧不能有空格! 变量名称全部用大写是编程惯例
ubuntu@VM-10-194-ubuntu:/tmp$ echo VAR
VAR
ubuntu@VM-10-194-ubuntu:/tmp$ echo $VAR
some
# 调用变量要加 $
[chen@localhost tmp]$ $val=hello
-bash: 1=hello: command not found
#$val表示变量存储的值,不能作为左值

1.2只读变量

格式 readonly val

[chen@localhost tmp]$ val=hello
[chen@localhost tmp]$ readonly val
[chen@localhost tmp]$ val=1
-bash: val: readonly variable

1.3删除变量

格式 unset val

1.4变量类型

运行shell时,会同时存在三种变量:

  • 局部变量 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
  • 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
  • shell变量 shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行

2.数组

2.1定义,使用

定义 数组名=(值1 值2 ... 值n) 或者 数组名[下标]=值
使用 ${数组名[下标]}

#创建 a=( )
ubuntu@VM-10-194-ubuntu:/tmp$ a=(1 2 3 f g)
ubuntu@VM-10-194-ubuntu:/tmp$ echo $a
1
#显示所有元素或者echo ${a[*]}    {}表示内部是一个整体,也可以 ${val},传入参数$10时也要${10}
ubuntu@VM-10-194-ubuntu:/tmp$ echo ${a[@]}
1 2 3 f g
#显示数组元素,0代表第1个元素
ubuntu@VM-10-194-ubuntu:/tmp$ echo ${a[2]}   
3
ubuntu@VM-10-194-ubuntu:/tmp$ a["sth"]=TT  #这样也行
ubuntu@VM-10-194-ubuntu:/tmp$ echo ${a[@]} 
TT 2 3 f g
#或者逐个创建
ubuntu@VM-10-194-ubuntu:/tmp$ a[6]=100
ubuntu@VM-10-194-ubuntu:/tmp$ echo ${a[@]}
TT 2 3 f g 100
#显示数组元素删除a[2]的值,并不删除a[2]
ubuntu@VM-10-194-ubuntu:/tmp$ unset a[2]   
ubuntu@VM-10-194-ubuntu:/tmp$ echo ${a[2]}

ubuntu@VM-10-194-ubuntu:/tmp$ unset a   #删除数组a所有元素
#${数组名[@或*]:起始位置:长度} 输出数组的第1-3项
ubuntu@VM-10-194-ubuntu:/tmp$ echo ${a[@]:0:3}
#${数组名[@或*]/查找字符/替换字符   替换输出,并不改变数组
ubuntu@VM-10-194-ubuntu:/tmp$ echo ${a[*]/1/6}

2.2获取数组长度

# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组单个元素的长度
lengthn=${#array_name[n]}

bash文件

1. 创建文件

ubuntu@VM-10-194-ubuntu:/tmp$ > test.sh
ubuntu@VM-10-194-ubuntu:/tmp$ touch test2.sh
ubuntu@VM-10-194-ubuntu:/tmp$ echo "something" >test3.sh
ubuntu@VM-10-194-ubuntu:/tmp$ cat test3.sh 
something

创建多行,使用了重定向的知识,重定向见本文后段

ubuntu@VM-10-194-ubuntu:/tmp$ cat >test4.sh<<EOF
> some
> shu wan zhi jie hui che
> zi dong tian jia >
> EOF
#EOF为任意字符串
ubuntu@VM-10-194-ubuntu:/tmp$ cat test4.sh 
some
shu wan zhi jie hui che
zi dong tian jia >

不过还是喜欢,vi file 直接输入
2. 添加执行权限

$ chmod +x test.sh 

3. 编写脚本

#!/bin/bash
echo "hello bash"
exit 0

说明:
#!/bin/bash : 它是bash文件声明语句,表示是以/bin/bash程序执行该文件。它必须写在文件的第一行!
echo "hello bash" : 表示在终端输出“hello bash”
exit 0 : 表示返回0。在bash中,0表示执行成功,其他表示失败。

4. 执行

ubuntu@VM-10-194-ubuntu:/tmp$ ./test.sh 
hello bash

注释

  • 单行注释 以“#”开头的行就是注释
  • 多行注释 sh里没有多行注释,可以把这一段要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果
zhushi()
{
zhushi注释内容
echo zhushi
}
:||{
被注释的多行内容
}

运算

1 数值运算

数值元算主要有4种实现方式:(())、let、expr、bc。
工作效率:
(()) == let > expr > bc

  • (())和let是bash内建命令,执行效率高,支持i++;而expr和bc是系统命令,会消耗内存,执行效率低。
  • 只有bc支持浮点运算

#!/bin/bash
#(())  要加个$再赋予变量
val=$((3*(5+2)))
echo $val

#let
let "val=3*(5+2)"
echo $val

#expr 又费劲  注意是`重音符  ``输出命令结果,例如val=`ls`,val=`date`
#还得用空格隔开运算符和数字,不然显示不对
val=`expr 3 \* \( 5 + 2 \)`
echo $val

#bc 是重音符`
val=`echo "3*(5+2)"|bc`
echo $val

使用$(())或let来进行整数计算,bc进行浮点数计算
$(( 3+3 ))
val=`echo "scale=3;1/3"|bc` 重音符
**i++ ((val++))或者 let val++

2 字符串运算

2.1字符串的使用


ubuntu@VM-10-194-ubuntu:/tmp$ str="hello world"
ubuntu@VM-10-194-ubuntu:/tmp$ echo ${str}
hello world
ubuntu@VM-10-194-ubuntu:/tmp$ echo ${strq:?ERR_MSG}
-bash: strq: ERR_MSG

2.2 字符串操作


ubuntu@VM-10-194-ubuntu:/tmp$ echo ${#str}
11
ubuntu@VM-10-194-ubuntu:/tmp$ echo ${str:3:6}
lo wor
ubuntu@VM-10-194-ubuntu:/tmp$ echo ${str%ld}
hello wor
#并不影响原字符串
ubuntu@VM-10-194-ubuntu:/tmp$ echo ${str}
hello world

流程控制(判断循环)

1 条件判断

1.1 test

语法

test EXPRESSION

test是关键字,表示判断;
EXPRESSION是被判断的语句。

1.1 数值判断

参数 说明
-eq 等于则为真
-ne 不等于则为真
-gt 大于则为真
-ge 大于等于则为真
-lt 小于则为真
-le 小于等于则为真
[chen@localhost tmp]$ test 12 -eq 2
[chen@localhost tmp]$ echo $?
1
# $?表示上一命令的执行结果(在linux中bash中,true返回0,false返回1

1.2字符串测试

参数 说明
= 等于则为真
!= 不相等则为真
-z 字符串 字符串的长度为零则为真
-n 字符串 字符串的长度不为零则为真

[chen@localhost tmp]$ test "hello" != "yes"
[chen@localhost tmp]$ echo $?
0

1.3文件测试

linux文件:目录、链接、设备、文本。。。

参数 说明
-e 文件名 如果文件存在则为真
-r 文件名 如果文件存在且可读则为真
-w 文件名 如果文件存在且可写则为真
-x 文件名 如果文件存在且可执行则为真
-s 文件名 如果文件存在且至少有一个字符则为真即文件长度大于0、非空
-d 文件名 如果文件存在且为目录则为真
-f 文件名 如果文件存在且为普通文件则为真
-L 文件名 如果文件存在且为符号连接
-c 文件名 如果文件存在且为字符型特殊文件则为真
-b 文件名 如果文件存在且为块特殊文件则为真
-u 文件名 如果文件存在且有suid位设置

ubuntu@VM-10-194-ubuntu:/tmp$ test -f ./123.txt 
ubuntu@VM-10-194-ubuntu:/tmp$ echo $?
0

1.2 []条件判断

语法

[ EXPRESSION ]

中括号的左右扩弧和EXPRESSION之间都必须有空格
空格空格
关于EXPRESSION的说明,参考如下:

ubuntu@VM-10-194-ubuntu:/tmp$ [ -f test2.sh ]
ubuntu@VM-10-194-ubuntu:/tmp$ echo $?
0
ubuntu@VM-10-194-ubuntu:/tmp$ [ -f test2.s11h ]
ubuntu@VM-10-194-ubuntu:/tmp$ echo $?
1

1.3 逻辑

基本格式(上表也有)
-a : 逻辑与,操作符两边均为真,结果为真,否则为假。
-o : 逻辑或,操作符两边一边为真,结果为真,否则为假。
! : 逻辑否,条件为假,结果为真。
[ expre ] && [ expre2 ] 与
[ expre ] || [ expre2 ] 或

#判断test2.sh是否可读写
[ -r test2.sh -a -w test2.sh ]

2 if [ ] ; then cmd; elif [ ] ; then cmd ; else cmd ; fi

if 或者 elif 后面必须有then,else直接跟命令,可以没有,最后以fi结尾
在bash文件中,回车,不需要分号,单行if命令需要分号
[] 可为 test、[]判断,计算式(( ))等,以下涉及判断条件同理
例1

 if [ 1 -eq 2 ] 
> then echo 1==2
> elif [ 2 -eq 3 ]
> then 2==3
> elif [ 3 -eq 4 ]
> then echo 3==4
> else echo 1=1 
> fi
#或者
if [ 1 -eq 2 ] ; then echo 1==2; elif [ 2 -eq 3 ]; then 2==3; elif [ 3 -eq 4 ]; then echo 3==4; else echo 1==1; fi
1==1

例2

#!/bin/bash
# 提示用户输入一个值
echo -n "please input a number:"
# 保存用户的输入到num中
read NUM
if [ $NUM -le 5 ] ;
then echo "$NUM<5";
else echo "$NUM>5";
#分号可有可无
fi
exit 0

3 case

# 格式
case 值 in
模式1}
命令1
...
;;
模式2)
命令2
...
;;
esac

#!/bin/bash
echo -n "are you femail(Y/N)"
read val
case $val in
Y|y)
echo "yes"
;;    # 注意此处有两个;
N|n)
echo "no"
;;
*)
echo "incorrect input"
;;
esac      # 注意esac结束
exit 0

4 for循环

for 变量名in列表  或者 for  ((i=1;i<7;i++)),**注意两个括号**
do
命令1
命令2...
done

# 判断当前目录下的文件并输出文件名
#!/bin/bash
#将ls结果保存到变量CUR,
CUR=`ls`    #注意这里是Tab键上面的`
# 大部分Unix shell以及编程语言如Perl、PHP以及Ruby等都以成对的重音符作指令替代,意思是以
某一个指令的输出结果作为另一个指令的输入项。例如上述指令
echo $CUR
for val in $CUR
do     #do不可少
if [ -f $val ] ;
then  echo "FILE: $val" ;
fi
done   #done 不可少
exit 0
#计算10以内数的和
#!/bin/bash
sum=0
for ((i=1;i<10;i++))
do
((sum=$sum+$i))
# (( ))表示数值计算
done
echo "sum=$sum"
exit 0

5 until

循环至少运行一次
当满足条件时不再执行直接结束

until 条件
do
命令1
...
done

例;输出5以内的自然数

#!/bin/bash
val=0
until (($val==5))   #或者[ "$val" -eq "5" ] 
do
echo $val
((val++))
done
exit 0

6 while

满足条件才进行循环,最少不运行

while 命令
do
命令1
命令2
...
done

例;输出5以内的自然数

#!/bin/bash
val=0
while ((val<5))
do
echo $val
((val=$val+1))
done
exit 0

7 break 与continue

break命令允许跳出循环-----结束
continue命令跳过这个循环步-----进入下个循环

例break输出5内自然数

#!/bin/bash
val=0
while true
do
if (($val==5));
then break;
fi
echo $val
((val++))
done
exit 0

例:从0开始逐步递增到10:当数值为5时,将数值递增2;否则,输出数值

#!/bin/bash
val=0
while (($val<=10))
do
if (($val==5))   #好像没有;用<Enter>也是可以的
then ((val=$val+2))
continue
else
echo $val 
((val++))
fi
done
exit 0

函数

所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可

1 定义

基本格式

function 函数名()
{
...
return 返回值;
}
  • function可有可无。但建议保留,因为保留的话看起来更加直观
  • return 返回值,如果不加,将以最后一条命令运行结果,作为返回值
#!/bin/bash
function foo()
{
echo "hello"
return 5;
}
foo
echo $?
#直接编写foo函数文件,在终端中运行foo“返回值为0”,没有echo结果

结果

[chen@localhost tmp]$ ./han
hello
5

2 传递参数

$n代表输入的第n个参数

foo param1 param2 param3
#参数变量出入函数内部为@ 例
echo $@
#输出结果为
param1 param2 param3
参数 说明
$? 显示上一条命令的退出状态。判断退出true为0,flase为1,函数退出结果为返回值,例
[chen@localhost tmp]$ ((1+1))
[chen@localhost tmp]$ echo $?
0
$# 传递到脚本的参数个数
$n 表示传入的第n个参数
$10 不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数
$* 以一个单字符串显示所有向脚本传递的参数。如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$0 当前sehll名 [chen@localhost tmp]$ echo $0 结果为-bash

$* 和 $@ 的区别

  • $* 和 $@ 表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1" "$2" … "$n" 的形式输出所有参数。
  • 但是当它们被双引号(" ")包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。

#!/bin/bash
for val in "$*"
do echo $val
done
echo \"
for val in "$@"
do echo $val
done
exit 0
ubuntu@VM-10-194-ubuntu:/tmp$ ./can 1 2 3 4
1 2 3 4
"
1
2
3
4

内建命令

1 内建指令查看

基本格式
type cmd
格式说明
type是命令关键字,cmd表示查看的命令;若输出builtin,则该命令是bash的内建命令。
例如:
ubuntu@VM-10-194-ubuntu:/tmp$ type echo
echo is a shell builtin
除此之外,用户也可以通过man bash或者man builtins查看bash的全部内置命令

2 常用内建命令

(01)echo
命令:echo arg
功能:在屏幕上显示出由arg指定的字串
(02)read
命令格式:read变量名表
功能:从标准输入设备读入一行,分解成若干字,赋值给bash程序内部定义的变量
(03)shift
命令:shift [N] (N为大于0的整数;当N省略时,等价与于“shift 1”)
功能:所有的参数依次向左移动N个位置,并使用$#减少N,直到$#=0为止。
(04)alias
命令:alias name='value'
功能:别名。用name替换value,value要用单引号括住。
(05)export
命令:export变量名[=变量值]
功能:export可以把bash的变量向下带入子bash(即子bash中可以使用父bash的变量),从而让子进程继承父进程中的环境变量。但子bash不能用export把它的变量向上带入父bash。
(06)readonly
命令:readonly 变量名
功能:定义只读变量。不带任何参数的readonly命令将显示出所有只读变量。
(07)exec
命令:exec 命令参数
功能:当bash执行到exec语句时,不会去创建新的子进程,而是转去执行指定的命令,当指定的命令执行完时,该进程(也就是最初的bash)就终止了,所以bash程序中exec后面的语句将不再 
被执行。
(08)"."(点)
命令:. bash程序文件名
功能:使bash读入指定的bash程序文件并依次执行文件中的所有语句。
(09)exit
命令:exit N
功能:退出Shell程序。在exit之后可有选择地指定一个数位作为返回状态。

echo

  • echo是Shell的一个内部指令,用于在屏幕上打印出指定的字符串。命令格式
echo "anything"
"可有可无
  • 1 显示转义字符 backslash escapes
    在echo命令的帮助中,写到默认禁止反斜杠功能。如果需要开起反斜杠转义功能,需要使用-e的参数。
转义字符 含义
\\ 反斜杠
\a 警报,响铃
\b 退格(删除键)
\f 换页(FF),将当前位置移到下页开头
\n 换行
\r 回车
\t 水平制表符(tab键)
\v 垂直制表符

#!/bin/bash
echo -e  "hello\c"
echo "hell\c"
echo  hell
exit 0

结果

hellohell\c
hell

可看到,需要 -e 才能启用转义字符功能
对于 " /需要// /" /$来输出,不适用上述规则

  • 2 显示变量
echo $val

当变量与其它字符相连时用{}隔开

echo ${val}-2-3 
  • 3 显示结果重定向至文件(写入另一个文件)
[chen@localhost tmp]$ echo rete >file
[chen@localhost tmp]$ cat file
rete
  • 4 原样输出字符串
    单引号
[chen@localhost tmp]$ echo '\$cal'
\$cal
  • 5 输出命令结果
    重音符`
[chen@localhost tmp]$ echo `date`
Mon Aug 7 00:23:33 PDT 2017

双引号可有可无,单引号主要用在原样输出中,重音符输出命令

printf

printf 命令用于格式化输出, 是echo命令的增强版。它是C语言printf()库函数的一个有限的变形,并且在语法上有些不同。

注意:printf 由 POSIX 标准所定义,移植性要比 echo 好。

格式

printf  format-string  [arguments...]
  • format-string 为格式控制字符串
  • arguments 为参数列表
[chen@localhost tmp]$ printf "%d%s%c%f\n" 1 "abc" "def" "0.1"
1abcd0.100000

%d %s %c %f 格式替代符详解:
d:data 数字 -- 对应位置参数必须是数字型,否则报错!
s:str 字符串 -- 对应位置参数必须是字符串或者字符型,否则报错!
c:char 字符 -- 对应位置参数必须是字符串或者字符型,否则报错!
f:float 浮点 -- 对应位置参数必须是数字型,否则报错!
如:上面第三个参数是 "def",%c 自动截取字符串的第一个字符作为结果输出,若第四个参数无0.1则输出0.000000

转义字符 含义
\\ 反斜杠
\a 警报,响铃
\b 退格(删除键)
\f 换页(FF),将当前位置移到下页开头
\n 换行
\r 回车
\t 水平制表符(tab键)
\v 垂直制表符
\c 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略
\ddd 表示1到3位数八进制值的字符。仅在格式字符串中有效
\0ddd 表示1到3位的八进制值字符

指定输出宽度
%-10s 指一个宽度为10个字符(-表示左对齐,没有则表示右对齐)
默认转义

转义字符 含义
\\ 反斜杠
\a 警报,响铃
\b 退格(删除键)
\f 换页(FF),将当前位置移到下页开头
\n 换行
\r 回车
\t 水平制表符(tab键)
\v 垂直制表符
\c 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略
\ddd 表示1到3位数八进制值的字符。仅在格式字符串中有效
\0ddd 表示1到3位的八进制值字符

与C语言printf()函数的不同

  • printf 命令不用加()
  • format-string 可以没有引号,但最好加上,单引号双引号均可,不加上运行结果偶尔异常,如
[chen@localhost tmp]$ printf "hello\n"
hello
[chen@localhost tmp]$ printf hello\n
hellon[chen@localhost tmp]$
  • 参数多于格式控制符(%)时,format-string 可以重用,可以将所有参数都转换,即未指定格式使用前面的格式
[chen@localhost tmp]$ printf "%s\n%s%s\n" 1 2 3
1
23
[chen@localhost tmp]$ printf "%s\n" 1 2 3    #格式不够使,借前面的格式
1
2
3
  • arguments 使用空格分隔,不用逗号。
[chen@localhost tmp]$ printf "%s\n" 1,2 3  #逗号不分隔,空格分隔
1,2
3

调试

1 bash命令调试

bash [-nvx] scripts.sh

选项与参数:

-n :不要执行 script,仅查询语法的问题;
-v :再执行 sccript 前,先将 scripts 的内容输出到屏幕上;
-x :将使用到的 script 内容显示到屏幕上,这是很有用的参数!
例如,想要执行bash脚本,并查看bash的调用流程,可以通过以下命令:
$ bash -x test.sh

2 echo调试

echo [OPTION] STRING
-n : 输出内容之后,不换行。默认是输入内容之后,换行。
-e : 开启反斜线“\”转义功能
-E : 关闭反斜线“\”转义功能(**默认**)。
例如,输出“please input a number:”之后不换行。
$ echo -n "please input a number:"

3 printf

和echo一样,printf也能用于输出。语法格式和C语言中printf一样。
例如,输出“hello printf”之后换行。
$ printf "hello printf\n"

输入输出重定向

标准输入,标准输出,标准错误输出
执行一个shell命令行时通常会自动打开三个标准文件,即

  • 标准输入文件(stdin),即shell的输入设备(linux里设备也是文件),通常对应终端的键盘;
  • 标准输出文件(stdout)为执行命令成功时将运行的结果输出到的文件
  • 标准错误输出到文件(stderr)为执行命令报错时将错误信息输出到的文件,这两个文件都对应终端的屏幕。

/dev下可以看到 stdin stdout stderr三个文件分别为标准输入,标准输出,标准错误输出,通过下面的例子可以看到 stdin stdout stderr分别连接到不同的文件

ubuntu@VM-10-194-ubuntu:/dev$ ls -all std*
lrwxrwxrwx 1 root root 15 Aug  7 09:34 stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Aug  7 09:34 stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 Aug  7 09:34 stdout -> /proc/self/fd/1

输入输出重定即: 改变输入/输出数据的的读取/输出的默认文件(键盘或终端)为其他文件(普通文件,文件描述符,文件设备),而且只能是文件

常用操作符

名称 默认文件描述符 操作符
标准输入(stdin) 0 < ,<<,0<或0<<
0<与<等价,其他带有文件描述符的操作符意义同理,<<代表追加
标准输出(stdout) 1 >, >>, 1> 或 1>>
标准错误输出(stderr) 2 2> 或 2>>

输入重定向

输入重定向是指把命令(或可执行程序)的标准输入重定向到指定的文件中。也就是说,输入可以不来自键盘,而来自一个指定的文件。所以说,输入重定向主要用于改变一个命令的输入源,特别是改变那些需要大量输入的输入源。

格式

命令 操作符 重定向文件

示例命令

格式 说明
Command < filename Command 命令以 filename 文件作为标准输入
Command < filename > filename2 Command 信不信以 filename 文件作为标准输入,以 filename 2 作为标准输出
注: 输入(>或>>) 与 输出(<或<<)无强制顺序 即wc >test<<delim与wc <<delim >test一样
Command << delimiter 从标准输入中读入,以 delimiter(任意) 为结束符,祥见示例

注: 上表格中的重定向仅在当前命令生效

wc 统计指定文件包含的行数、单词数和字符数

#当只输入wc时,回等待用户输入,直至 ctrl+d停止,然后统计行数、单词数和字符数
ubuntu@VM-10-194-ubuntu:/tmp$ wc
123 34
23      1       3       9
# 也可将输入重定向为某个文件
ubuntu@VM-10-194-ubuntu:/tmp$ wc < file
13 13 95
ubuntu@VM-10-194-ubuntu:/tmp$ wc <<delim
> haha
> test
> lala
> delim
 3  3 15
#或者,将结果输出到test中
ubuntu@VM-10-194-ubuntu:/tmp$ wc >test<<delim
> haha
> test
> lala
> delim
ubuntu@VM-10-194-ubuntu:/tmp$ cat test
 3  3 15

输出重定向

输出重定向是指把命令(或可执行程序)的标准输出或标准错误输出重新定向到指定文件中。这样,该命令的输出就不显示在屏幕上,而是写入到指定文件中。

输出重定向比输入重定向更常用,很多情况下都可以使用这种功能。例如,如果某个命令的输出很多,在屏幕上不能完全显示,那么将输出重定向到一个文件中,然后 再用文本编辑器打开这个文件,就可以查看输出信息;如果想保存一个命令的输出,也可以使用这种方法。

格式

命令 操作符 重定向文件

注意标准输出和标准错误输出不是"一个"文件,所以有两个输出,只改一个的话,另一个不变,同时改变需要2>file 1>file(意思是标准输出到file,标准错误输出到file),或者>file 2>&1(表示标准输出到file,标准错误输出到标准输出的文件即file)或者&>file (意思是把 标准输出 和 标准错误输出 都重定向到文件file中)
>>为追加输入,即在原文件内末尾添加
示例命令

格式 说明
Command > filename 把标准输出重定向到一个新文件中
Command >> filename 把标准输出重定向到一个文件(追加)
Command 2> filename 把标准错误重定向到一个文件中
Command 2>> filename 把标准错误重定向到一个文件中(追加)
Command > filename 2>&1 把标准输出和错误一起重定向到一个文件中
Command >> filename 2>&1 把标准输出和错误一起重定向到一个文件中(追加)

注: 上表格中的重定向仅在当前命令生效

ubuntu@VM-10-194-ubuntu:/tmp$ ls vv >file
ubuntu@VM-10-194-ubuntu:/tmp$ ls vv >>file
ubuntu@VM-10-194-ubuntu:/tmp$ cat file
vv
vv

绑定重定向

前两种重定向仅生效一次,绑定重定向即永久重定向输入输出文件,所有命令的输入输出都都来自重定向后的文件
格式

exec 操作符 重定向文件

操作符 < 0< << > 1> .... 与之前意义相同

# 将输出绑定重定向到/tmp/test后命令的结果不会输出到终端
ubuntu@VM-10-194-ubuntu:/tmp$ exec >/tmp/test
ubuntu@VM-10-194-ubuntu:/tmp$ ls
ubuntu@VM-10-194-ubuntu:/tmp$ ls -11
# 将输出重定向回/dev/tty(注意必须写完整路径)则终端又输出命令运行结果
ubuntu@VM-10-194-ubuntu:/tmp$ exec >/dev/tty
ubuntu@VM-10-194-ubuntu:/tmp$ ls
!  1  cal.sh  cancan  cvm_init.log  ff    net_affinity.log  sagent.pid  test  vv
0  2  can     chon    ec            file  pin               setRps.log  tty

文件描述符

文件描述符,可以理解为文件的一个数字标记

  • &0代表标准输入文件的标记为0
  • &1 代表标准输出文件标记为1
  • &2代表标准错误输出
  • &-代表关闭与它绑定的描述符

&n 代表是已经存在的文件描述符,在重定向时与文件地位相同,即重定向的文件也可以用文件描述符来表示

格式

#指定m描述的文件
命令 m>file
#一般为一次性重定向,绑定重定向命令为exec,
# file也可以为&n,这样m->n->n描述的文件

示例命令

格式 说明
Command >&n 把标准输出重定向到文件描述符 n 中,如 ls >&1 ,若要实现绑定重定向则Command为exec如 exec >&n
Command m>&n 把往文件描述符 m 的输出重定向到文件描述符 n 上,2>&1,若要实现绑定重定向则 exec m>&n
Command <&- 关闭标准输入同样绑定则Command为exec
Command 2>&- 关闭标准错误输出,和 2>/dev/null 有类似功效,同样绑定则Command为exec
Command n>&- 关闭输出文件描述符n,和 2>/dev/null 有类似功效,同样绑定则Command为exec

ubuntu@VM-10-194-ubuntu:/tmp$ exec 6>&1
#原理: 6 -> 1 -> stdout -> /dev/tty
ubuntu@VM-10-194-ubuntu:/tmp$ exec 1>test.txt
#原理: 1->test.txt 同时 stdout -> test.txt
ubuntu@VM-10-194-ubuntu:/tmp$ ls
#原理: ls结果输出到/tmp/test.txt了
ubuntu@VM-10-194-ubuntu:/tmp$ exec 1>&6
#原理: 1-> 6 -> /dev/tty 同时 stdout -> /dev/tty,也可直接exec 1>/dev/tty或者 exec 1>&2
ubuntu@VM-10-194-ubuntu:/tmp$ ls
cvm_init.log  net_affinity.log  sagent.pid  setRps.log  test.txt
#原理: ls结果输出到/dev/tty即终端
ubuntu@VM-10-194-ubuntu:/tmp$ ls /dev/fd
0  1  2  3  6
#添加文件描述符后在/dev/fd里可以看到
ubuntu@VM-10-194-ubuntu:/tmp$ exec 6>&-
#
ubuntu@VM-10-194-ubuntu:/tmp$ ls /dev/fd
0  1  2  3

备注

1. > < n>等操作符可以同时出现在一条命令里,而且无顺序要求,如
ubuntu@VM-10-194-ubuntu:/tmp$ exec 1>test 2>/dev/tty
2. 命令行前面这一条ubuntu@VM-10-194-ubuntu:/tmp$以及输入的命令在键盘上的显示好像属于标准错误输出
3. 命令 < 文件 中的命令应该能接受标准输入 ,命令 > 文件中的命令应该有标准输出
4. 在类Unix系统中,/dev/null,或称空设备,是一个特殊的设备文件,它丢弃一切写入其中的数据(但报告写入操作成功),读取它则会立即得到一个EOF,可以重定向输出到/dev/null

其他传递

管道

将一个程序或命令的输出作为另一个程序或命令的输入,有两种方法,一种是通过一个临时文件将两个命令或程序结合在一起,例如

ubuntu@VM-10-194-ubuntu:/tmp$ ls > test
ubuntu@VM-10-194-ubuntu:/tmp$ cat test
cvm_init.log
net_affinity.log
sagent.pid
setRps.log
test

另一种是Linux所提供的管道功能。

ubuntu@VM-10-194-ubuntu:/tmp$ ls | cat
cvm_init.log
net_affinity.log
sagent.pid
setRps.log
test

管道工作流程


command1正确输出,作为command2的输入 然后comand2的输出作为,comand3的输入 ,comand3输出就会直接显示在屏幕上面了。

通过管道之后:comand1,comand2的正确输出不显示在屏幕上面

注意:

  1. 管道命令只处理前一个命令正确输出,不处理错误输出
  2. 管道命令右边命令,必须能够接收标准输入流命令才行

管道与重定向的区别

  1. 管道
    左边的命令应该有标准输出 | 右边的命令应该接受标准输入
    重定向
    左边的命令应该有标准输出 > 右边只能是文件
    左边的命令应该需要标准输入 < 右边只能是文件
  2. 管道触发两个子进程执行|两边的程序;而重定向是在一个进程内执行
#可以相互转换情况
#输入重定向
 
[chengmo@centos5 shell]$ cat test.sh| grep -n 'echo'
5:    echo "very good!";
7:    echo "good!";
9:    echo "pass!";
11:    echo "no pass!";
#"|"管道两边都必须是shell命令
 
 
[chengmo@centos5 shell]$ grep -n 'echo' <test.sh    
5:    echo "very good!";
7:    echo "good!";
9:    echo "pass!";
11:    echo "no pass!";
#"重定向"符号,右边只能是文件(普通文件,文件描述符,文件设备)
 
 
[chengmo@centos5 shell]$ mail -s 'test' 8292669@qq.com <test.sh
[chengmo@centos5 shell]$ cat test.sh|mail -s 'test' 8292669@qq.com
#以上2个也相同,将test.sh内容发送到指定邮箱。
 
 
[chengmo@centos5 shell]$ (sed -n '1,$p'|grep -n 'echo')<test.sh 
5:    echo "very good!";
7:    echo "good!";
9:    echo "pass!";
11:    echo "no pass!";
#这个脚本比较有意思了。由于前面是管道,后面需要把test.sh内容重定向到 sed ,然后sed输出通过管道,输入给grep.需要将前面用"()"运算符括起来。在单括号内的命令,可以把它们看作一个象一个命令样。如果不加括号test.sh就是grep 的输入了。
 
 
#上面一个等同于这个
[chengmo@centos5 shell]$ sed -n '1,$p'<test.sh | grep -n 'echo'
5:    echo "very good!";
7:    echo "good!";
9:    echo "pass!";
11:    echo "no pass!";
 
#重定向运算符,在shell命令解析前,首先检查的(一个命令,执行前一定检查好它的输入,输出,也就是0,1,2 设备是否准备好),所以优先级会最高
 
 
[chengmo@centos5 shell]$ sed -n '1,10p'<test.sh | grep -n 'echo' <testsh.sh
10:echo $total;
18:echo $total;
21:     echo "ok";
#哈哈,这个grep又接受管道输入,又有testsh.sh输入,那是不是2个都接收呢。刚才说了"<"运算符会优先,管道还没有发送数据前,grep绑定了testsh.sh输入,这样sed命令输出就被抛弃了。这里一定要小心使用
 
#输出重定向
 
[chengmo@centos5 shell]$ cat test.sh>test.txt
[chengmo@centos5 shell] cat test.sh|tee test.txt &>/dev/null
#通过管道实现将结果存入文件,还需要借助命令tee,它会把管道过来标准输入写入文件test.txt ,然后将标准输入复制到标准输出(stdout),所以重定向到/dev/null 不显示输出
#">"输出重定向,往往在命令最右边,接收左边命令的,输出结果,重定向到指定文件。也可以用到命令中间。
 
 
[chengmo@centos5 shell]$ ls test.sh test1.sh testsh.sh 2>err.txt | grep 'test'
test.sh
testsh.sh
#目录下面有:test,testsh文件,test1.sh不存在,因此将ls 命令错误输出输入到err.txt 正确输出,还会通过管道发送到grep命令。
[chengmo@centos5 shell]$ ls test.sh test1.sh testsh.sh &>err.txt | grep 'test'
#这次打印结果是空,&代表正确与错误输出 都输入给err.txt,通过管道继续往下面传递数据为空,所以没有什么显示的
 
#同样">"输出重定向符,优先级也是先解析,当一个命令有这个字符,它就会与左边命令标准输出绑定。准备好了这些,就等待命令执行输出数据,它就开始接收

命令替换(重音符`)

命令替换和重定向有些相似,但区别在于命令替换是将一个命令的输出作为另外一个命令的参数

重定向必须为一个文件,而重音符``是将命令的结果作为参数传递例如

ubuntu@VM-10-194-ubuntu:/tmp$ echo 192.168.1.1 > file
# ping需要参数,不是文件,即不能接受标准输入,可以接受重音符运行的参数,不能接受重定向的输入文件
ubuntu@VM-10-194-ubuntu:/tmp$ ping `cat file`
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
^Z
[8]+  Stopped                 ping `cat file`
ubuntu@VM-10-194-ubuntu:/tmp$ echo 192.168.1.1 >file
ubuntu@VM-10-194-ubuntu:/tmp$ ping < file
Usage: ping [-aAbBdDfhLnOqrRUvV]...省略
##cat 可以接收文件,也可以接受参数,即可以接受标准输入
ubuntu@VM-10-194-ubuntu:/tmp$ cat file
192.168.1.1
ubuntu@VM-10-194-ubuntu:/tmp$ cat < file
192.168.1.1
ubuntu@VM-10-194-ubuntu:/tmp$ cat `echo file`
192.168.1.1

还有好多需要学的,留在下篇继续

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,149评论 2 34
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • Ubuntu的发音 Ubuntu,源于非洲祖鲁人和科萨人的语言,发作 oo-boon-too 的音。了解发音是有意...
    萤火虫de梦阅读 99,215评论 9 467
  • 基础命令 主要的命令和快捷键 Linux系统命令由三部分组成:cmd + [options]+[operation...
    485b1aca799e阅读 1,088评论 0 0
  • 基础 头文件 #!/bin/bash 或者#!/bin/sh #!约定的标记,如IOS的Import 执行文件时需...
    ZMJun阅读 1,229评论 1 2