前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >shell极简教程(二)

shell极简教程(二)

作者头像
架构师小秘圈
发布2018-04-02 17:39:44
5.2K0
发布2018-04-02 17:39:44
举报
文章被收录于专栏:架构师小秘圈架构师小秘圈

一,题记

不懂shell的程序员不是好程序员,学习shell是为了自动化,使用自动化可以非常有效的提高工作效率。没有一个大公司不要求linux的基本技能的,只是不同岗位要求掌握的程度不同。在第一篇 shell极简教程 已经对shell进行了简单的介绍,本篇进行更进一步的介绍!

二,shell注释

以“#”开头的行就是注释,会被解释器忽略。

  sh里没有多行注释,只能每一行加一个#号。只能像这样:

代码语言:javascript
复制
#--------------------------------------------
# 这是一个自动打ipa的脚本,基于webfrogs的ipa-build书写:
# https://github.com/webfrogs/xcode_shell/blob/master/ipa-build# 功能:自动为etao ios app打包,产出物为14个渠道的ipa包
# 特色:全自动打包,不需要输入任何参数
#--------------------------------------------
##### 用户配置区 开始 #####
#
#
# 项目根目录,推荐将此脚本放在项目的根目录,这里就不用改了
# 应用名,确保和Xcode里Product下的target_name.app名字一致
#
##### 用户配置区 结束 #####

  如果在开发过程中,遇到大段的代码需要临时注释起来,过一会儿又取消注释,怎么办呢?每一行加个#符号太费力了,可以把这一段要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果。

三,shell字符串

字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号,也可以用双引号,也可以不用引号。单双引号的区别跟PHP类似。

单引号

代码语言:javascript
复制
str='this is a string'

单引号字符串的限制:

  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
  • 单引号字串中不能出现单引号(对单引号使用转义符后也不行)。

双引号

代码语言:javascript
复制
your_name='qinjx'
str="Hello, I know your are \"$your_name\"! \n"

双引号的优点:

  • 双引号里可以有变量
  • 双引号里可以出现转义字符

拼接字符串

代码语言:javascript
复制
your_name="qinjx"
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting $greeting_1

获取字符串长度

代码语言:javascript
复制
string="abcd"
echo ${#string} #输出 4

提取子字符串

代码语言:javascript
复制
string="alibaba is a great company"
echo ${string:1:4} #输出liba

查找子字符串

代码语言:javascript
复制
string="alibaba is a great company"
echo `expr index "$string" is`

四,shell数组

Shell在编程方面比Windows批处理强大很多,无论是在循环、运算。

bash支持一维数组(不支持多维数组),并且没有限定数组的大小。类似与C语言,数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0。

定义数组

在Shell中,用括号来表示数组,数组元素用“空格”符号分割开。定义数组的一般形式为:   array_name=(value1 ... valuen)   例如:

代码语言:javascript
复制
array_name=(value0 value1 value2 value3)

或者

代码语言:javascript
复制
array_name=(
value0
value1
value2
value3
)

  还可以单独定义数组的各个分量:

代码语言:javascript
复制
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2

  可以不使用连续的下标,而且下标的范围没有限制。

读取数组

  读取数组元素值的一般格式是:   ${array_name[index]}   例如:

代码语言:javascript
复制
valuen=${array_name[2]}

  举个例子:

代码语言:javascript
复制
#!/bin/sh
NAME[0]="Zara"
NAME[1]="Qadir"
NAME[2]="Mahnaz"
NAME[3]="Ayan"
NAME[4]="Daisy"
echo "First Index: ${NAME[0]}"
echo "Second Index: ${NAME[1]}"

  运行脚本,输出:

代码语言:javascript
复制
$./test.sh
First Index: Zara
Second Index: Qadir

  使用@ 或 * 可以获取数组中的所有元素,例如:

代码语言:javascript
复制
${array_name[*]}
${array_name[@]}

  举个例子:

代码语言:javascript
复制
#!/bin/sh
NAME[0]="Zara"
NAME[1]="Qadir"
NAME[2]="Mahnaz"
NAME[3]="Ayan"
NAME[4]="Daisy"
echo "First Method: ${NAME[*]}"
echo "Second Method: ${NAME[@]}"

  运行脚本,输出:

代码语言:javascript
复制
$./test.sh
First Method: Zara Qadir Mahnaz Ayan Daisy
Second Method: Zara Qadir Mahnaz Ayan Daisy

获取数组的长度

获取数组长度的方法与获取字符串长度的方法相同,例如:

代码语言:javascript
复制
# 取得数组元素的个数
length=${#array_name[@]}# 
或者
length=${#array_name[*]}# 
取得数组单个元素的长度
lengthn=${#array_name[n]}

五,echo命令

echo是Shell的一个内部指令,用于在屏幕上打印出指定的字符串。命令格式:

代码语言:javascript
复制
echo arg

  您可以使用echo实现更复杂的输出格式控制。

显示转义字符

代码语言:javascript
复制
echo "\"It is a test\""

  结果将是:

代码语言:javascript
复制
"It is a test"

  双引号也可以省略。

显示变量

代码语言:javascript
复制
name="OK"echo "$name It is a test"

  结果将是:

代码语言:javascript
复制
OK It is a test

  同样双引号也可以省略。   如果变量与其它字符相连的话,需要使用大括号({ }):

代码语言:javascript
复制
mouth=8echo "${mouth}-1-2009"

  结果将是:

代码语言:javascript
复制
8-1-2009

显示换行

代码语言:javascript
复制
echo "OK!\n"echo "It is a test"

  输出:

代码语言:javascript
复制
OK!
It is a test

显示不换行

代码语言:javascript
复制
echo "OK!\c"echo "It is a test"

  输出:

代码语言:javascript
复制
OK!It si a test

显示结果重定向至文件

代码语言:javascript
复制
echo "It is a test" > myfile

原样输出字符串

  若需要原样输出字符串(不进行转义),请使用单引号。例如:

代码语言:javascript
复制
echo '$name\"'

显示命令执行结果

代码语言:javascript
复制
echo `date`

  结果将显示当前日期   从上面可看出,双引号可有可无,单引号主要用在原样输出中。

六,printf命令

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

  注意:printf 由 POSIX 标准所定义,移植性要比 echo 好。   如同 echo 命令,printf 命令也可以输出简单的字符串:

代码语言:javascript
复制
$printf "Hello, Shell\n"Hello, Shell
$

  printf 不像 echo 那样会自动换行,必须显式添加换行符(\n)。   printf 命令的语法:

代码语言:javascript
复制
printf  format-string  [arguments...]

  format-string 为格式控制字符串,arguments 为参数列表。   这里仅说明与C语言printf()函数的不同:

  • printf 命令不用加括号
  • format-string 可以没有引号,但最好加上,单引号双引号均可。
  • 参数多于格式控制符(%)时,format-string 可以重用,可以将所有参数都转换。
  • arguments 使用空格分隔,不用逗号。

  请看下面的例子:

代码语言:javascript
复制
$ printf "%d %s\n" 1 "abc"
1 abc
# 单引号与双引号效果一样
$ printf '%d %s\n' 1 "abc"
1 abc
# 没有引号也可以输出
$ printf %s abcdef
abcdef
# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
$ printf %s abc def
abcdef
$ printf "%s\n" abc def
abcdef
$ printf "%s %s %s\n" a b c d e f g h i j
a b c
d e f
g h i
j
# 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替$ printf "%s and %d \n"
and 0
# 如果以 %d 的格式来显示字符串,那么会有警告,提示无效的数字,此时默认置为 0
$ printf "The first program always prints'%s,%d\n'" Hello Shell-bash: printf: Shell: invalid number
The first program always prints 'Hello,0'$

  注意,根据POSIX标准,浮点格式%e、%E、%f、%g与%G是“不需要被支持”。这是因为awk支持浮点预算,且有它自己的printf语句。这样Shell程序中需要将浮点数值进行格式化的打印时,可使用小型的awk程序实现。然而,内建于bash、ksh93和zsh中的printf命令都支持浮点格式。

七,if...else语句

if 语句通过关系运算符判断表达式的真假来决定执行哪个分支。Shell 有三种 if ... else 语句:

  • if ... fi 语句;
  • if ... else ... fi 语句;
  • if ... elif ... else ... fi 语句。

if ... else 语句

  if ... else 语句的语法:

代码语言:javascript
复制
if [ expression ]
then
   Statement(s) to be executed if expression is true
fi

  如果 expression 返回 true,then 后边的语句将会被执行;如果返回 false,不会执行任何语句。   最后必须以 fi 来结尾闭合 if,fi 就是 if 倒过来拼写,后面也会遇见。   注意:expression 和方括号([ ])之间必须有空格,否则会有语法错误。   举个例子:

代码语言:javascript
复制
#!/bin/sha=10b=20if [ $a == $b ]
then
echo "a is equal to b"fiif [ $a != $b ]
then
echo "a is not equal to b"fi

  运行结果:

代码语言:javascript
复制
a is not equal to b

if ... else ... fi 语句

  if ... else ... fi 语句的语法:

代码语言:javascript
复制
if [ expression ]
then
   Statement(s) to be executed if expression is true
else
   Statement(s) to be executed if expression is not true
fi

  如果 expression 返回 true,那么 then 后边的语句将会被执行;否则,执行 else 后边的语句。   举个例子:

代码语言:javascript
复制
#!/bin/sha=10b=20if [ $a == $b ]
then
echo "a is equal to b"elseecho "a is not equal to b"fi

  执行结果:

代码语言:javascript
复制
a is not equal to b

if ... elif ... fi 语句

  if ... elif ... fi 语句可以对多个条件进行判断,语法为:

代码语言:javascript
复制
if [ expression 1 ]
then
   Statement(s) to be executed if expression 1 is true
elif [ expression 2 ]
then
   Statement(s) to be executed if expression 2 is true
elif [ expression 3 ]
then
   Statement(s) to be executed if expression 3 is true
else
   Statement(s) to be executed if no expression is true
fi

  哪一个 expression 的值为 true,就执行哪个 expression 后面的语句;如果都为 false,那么不执行任何语句。   举个例子:

代码语言:javascript
复制
#!/bin/sha=10b=20if [ $a == $b ]
then
echo "a is equal to b"elif [ $a -gt $b ]
then
echo "a is greater than b"elif [ $a -lt $b ]
then
echo "a is less than b"elseecho "None of the condition met"fi

  运行结果:

代码语言:javascript
复制
a is less than b

  if ... else 语句也可以写成一行,以命令的方式来运行,像这样:

代码语言:javascript
复制
if test $[2*3] -eq $[1+5]; then echo 'The two numbers are equal!'; fi;

  if ... else 语句也经常与 test 命令结合使用,如下所示:

代码语言:javascript
复制
num1=$[2*3]
num2=$[1+5]if test $[num1] -eq $[num2]
then
echo 'The two numbers are equal!'elseecho 'The two numbers are not equal!'fi

  输出:

代码语言:javascript
复制
The two numbers are equal!

  test 命令用于检查某个条件是否成立,与方括号([ ])类似。

八,case esac命令

case ... esac 与其他语言中的 switch ... case 语句类似,是一种多分枝选择结构。   case 语句匹配一个值或一个模式,如果匹配成功,执行相匹配的命令。case语句格式如下:

  case 值 in

代码语言:javascript
复制
模式1)
    command1
    command2
    command3
    ;;
模式2)
    command1
    command2
    command3
    ;;
*)
    command1
    command2
    command3
    ;;
esac

  case工作方式如上所示。取值后面必须为关键字 in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。;; 与其他语言中的 break 类似,意思是跳到整个 case 语句的最后。   取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。   下面的脚本提示输入1到4,与每一种模式进行匹配:

代码语言:javascript
复制
echo 'Input a number between 1 to 4'
echo 'Your number is:\c'
read aNum
case $aNum in
1) echo 'You select 1';;
2) echo 'You select 2';;
3) echo 'You select 3';;
4) echo 'You select 4';;
*) echo 'You do not select a number between 1 to 4';;
esac

  输入不同的内容,会有不同的结果,例如:

代码语言:javascript
复制
Input a number between 1 to 4
Your number is:3
You select 3

  再举一个例子:

代码语言:javascript
复制
#!/bin/bash
option="${1}"
case ${option} in
-f) FILE="${2}"
echo "File name is $FILE";;
-d) DIR="${2}"
echo "Dir name is $DIR";;*)
echo "`basename ${0}`:usage: [-f file] | [-d directory]"
exit 1 
;;
esac

  运行结果:

代码语言:javascript
复制
$./test.sh
test.sh: usage: [ -f filename ] | [ -d directory ]
$ ./test.sh -f index.htm
$ vi test.sh
$ ./test.sh -f index.htm
File name is index.htm
$ ./test.sh -d unix
Dir name is unix
$

九,for循环

与其他编程语言类似,Shell支持for循环。

  for循环一般格式为:

代码语言:javascript
复制
for 变量 in 列表
do
    command1
    command2
    ...
    commandN
done

  列表是一组值(数字、字符串等)组成的序列,每个值通过空格分隔。每循环一次,就将列表中的下一个值赋给变量。   in 列表是可选的,如果不用它,for 循环使用命令行的位置参数。   例如,顺序输出当前列表中的数字:

代码语言:javascript
复制
for loop in 1 2 3 4 5do
echo "The value is: $loop"done

  运行结果:

代码语言:javascript
复制
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5

  顺序输出字符串中的字符:

代码语言:javascript
复制
for str in 'This is a string'
do
echo $str
done

  运行结果:

代码语言:javascript
复制
This is a string

  显示主目录下以 .bash 开头的文件:

代码语言:javascript
复制
#!/bin/bash
for FILE in $HOME/.bash*
do
echo $FILE
done

  运行结果:

代码语言:javascript
复制
/root/.bash_history
/root/.bash_logout
/root/.bash_profile
/root/.bashrc

十,while循环

while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件。其格式为:

代码语言:javascript
复制
while command
do
   Statement(s) to be executed if command is true
done

  命令执行完毕,控制返回循环顶部,从头开始直至测试条件为假。   以下是一个基本的while循环,测试条件是:如果COUNTER小于5,那么返回 true。COUNTER从0开始,每次循环处理时,COUNTER加1。运行上述脚本,返回数字1到5,然后终止。

代码语言:javascript
复制
COUNTER=0
while [ $COUNTER -lt 5 ]
do
COUNTER='expr $COUNTER+1'
echo $COUNTER
done

运行脚本,输出:

代码语言:javascript
复制
1
2
3
4
5

  while循环可用于读取键盘信息。下面的例子中,输入信息被设置为变量FILM,按<Ctrl-D>结束循环。

代码语言:javascript
复制
echo 'type <CTRL-D> to terminate'
echo -n 'enter your most liked film: '
while read FILM
do
echo "Yeah! great film the $FILM"
done

运行脚本,输出类似下面:

代码语言:javascript
复制
type <CTRL-D> to terminate
enter your most liked film: Sound of Music
Yeah! great film the Sound of Music

十一,until命令

until 循环执行一系列命令直至条件为 true 时停止。until 循环与 while 循环在处理方式上刚好相反。一般while循环优于until循环,但在某些时候,也只是极少数情况下,until 循环更加有用。   until 循环格式为:

代码语言:javascript
复制
until command
do
   Statement(s) to be executed until command is true
done

  command 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。   例如,使用 until 命令输出 0 ~ 9 的数字:

代码语言:javascript
复制
#!/bin/basha=0
until [ ! $a -lt 10 ]
do
echo $a
a=`expr $a + 1`
done

  运行结果:

代码语言:javascript
复制
01
2
3
4
5
6
7
8
9

十二,跳出循环

在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,像大多数编程语言一样,Shell也使用 break 和 continue 来跳出循环。

break命令

  break命令允许跳出所有循环(终止执行后面的所有循环)。   下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,就要使用break命令。

代码语言:javascript
复制
#!/bin/bash
while :
do
echo -n "Input a number between 1 to 5: "
read aNum
case $aNum in
1|2|3|4|5) echo "Your number is $aNum!"
;;
*) echo "You do not select a number between 1 to 5, game is over!"break;;
esac
done

  在嵌套循环中,break 命令后面还可以跟一个整数,表示跳出第几层循环。例如:

代码语言:javascript
复制
break n

  表示跳出第 n 层循环。   下面是一个嵌套循环的例子,如果 var1 等于 2,并且 var2 等于 0,就跳出循环:

代码语言:javascript
复制
#!/bin/bash
for var1 in 1 2 3
do
for var2 in 0 5
do
if [ $var1 -eq 2 -a $var2 -eq 0 ]
then
break 2
else
echo "$var1 $var2"
fi
done
done

如上,break 2 表示直接跳出外层循环。运行结果:

代码语言:javascript
复制
1 0
1 5

continue命令

  continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。   对上面的例子进行修改:

代码语言:javascript
复制
#!/bin/bash
while :
do
echo -n "Input a number between 1 to 5: "
read aNum
case $aNum in
1|2|3|4|5) echo "Your number is $aNum!";;
*) echo "You do not select a number between 1 to 5!"
continue
echo "Game is over!"
;;
esac
done

  运行代码发现,当输入大于5的数字时,该例中的循环不会结束,语句

代码语言:javascript
复制
echo "Game is over!"

  永远不会被执行。   同样,continue 后面也可以跟一个数字,表示跳出第几层循环。   再看一个 continue 的例子:

代码语言:javascript
复制
#!/bin/bash
NUMS="1 2 3 4 5 6 7"
for NUM in $NUMS
do
Q=`expr $NUM % 2`
if [ $Q -eq 0 ]
then
echo "Number is an even number!!"
continue
fi
echo "Found odd number"
done

  运行结果:

代码语言:javascript
复制
Found odd number
Number is an even number!!
Found odd number
Number is an even number!!
Found odd number
Number is an even number!!
Found odd number

十三,Shell函数

函数可以让我们将一个复杂功能划分成若干模块,让程序结构更加清晰,代码重复利用率更高。像其他编程语言一样,Shell 也支持函数。Shell 函数必须先定义后使用。

  Shell 函数的定义格式如下:

代码语言:javascript
复制
function_name () {
    list of commands
    [ return value ]
}

  如果你愿意,也可以在函数名前加上关键字 function:

代码语言:javascript
复制
function function_name () {
    list of commands
    [ return value ]
}

  函数返回值,可以显式增加return语句;如果不加,会将最后一条命令运行结果作为返回值。   Shell 函数返回值只能是整数,一般用来表示函数执行成功与否,0表示成功,其他值表示失败。如果 return 其他数据,比如一个字符串,往往会得到错误提示:“numeric argument required”。   如果一定要让函数返回字符串,那么可以先定义一个变量,用来接收函数的计算结果,脚本在需要的时候访问这个变量来获得函数返回值。=   先来看一个例子:

代码语言:javascript
复制
#!/bin/bash
# Define your function here
Hello () {
echo "Url is  
# Invoke your function
Hello

  运行结果:

代码语言:javascript
复制
$./test.sh
Hello World
$

  调用函数只需要给出函数名,不需要加括号。   再来看一个带有return语句的函数:

代码语言:javascript
复制
#!/bin/bash
funWithReturn(){
echo "The function is to get the sum of two numbers..."
echo -n "Input first number: "
read aNum
echo -n "Input another number: "
read anotherNum
echo "The two numbers are $aNum and $anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn
# Capture value returnd by last commandret=$?
echo "The sum of two numbers is $ret !"

  运行结果:

代码语言:javascript
复制
The function is to get the sum of two numbers...
Input first number: 25
Input another number: 50
The two numbers are 25 and 50 !
The sum of two numbers is 75 !

  函数返回值在调用该函数后通过 $? 来获得。   再来看一个函数嵌套的例子:

代码语言:javascript
复制
#!/bin/bash
# Calling one function from another
number_one () {
echo "Url_1 is  
number_two
}
number_two () {
echo "Url_2 is http://see.xidian.edu.cn/cpp/u/xitong/"}
number_one

  运行结果:

代码语言:javascript
复制
Url_1 is  
Url_2 is http://see.xidian.edu.cn/cpp/u/xitong/

  像删除变量一样,删除函数也可以使用 unset 命令,不过要加上 .f 选项,如下所示:

代码语言:javascript
复制
$unset .f function_name

  如果你希望直接从终端调用函数,可以将函数定义在主目录下的 .profile 文件,这样每次登录后,在命令提示符后面输入函数名字就可以立即调用。

十四,shell函数参数

在Shell中,调用函数时可以向其传递参数。在函数体内部,通过

n的形式来获取参数的值,例如,n的形式来获取参数的值,例如,1表示第一个参数,$2表示第二个参数...

  带参数的函数示例:

代码语言:javascript
复制
#!/bin/bashfunWithParam(){
echo "The value of the first parameter is $1 !"
echo "The value of the second parameter is $2 !"
echo "The value of the tenth parameter is $10 !"
echo "The value of the tenth parameter is ${10} !"
echo "The value of the eleventh parameter is ${11} !"
echo "The amount of the parameters is $# !" # 参数个数
echo "The string of the parameters is $* !" # 传递给函数的所有参数}
funWithParam 1 2 3 4 5 6 7 8 9 34 73

  运行脚本:

代码语言:javascript
复制
The value of the first parameter  1 2 10 34 73 12 1 2 3 4 5 6 7 8 9 34 73 !

注意,10不能获取第十个参数,获取第十个参数需要10不能获取第十个参数,获取第十个参数需要{10}。当n>=10时,需要使用${n}来获取参数。   另外,还有几个特殊变量用来处理参数,前面已经提到:

特殊变量

说明

$#

传递给函数的参数个数。

$*

显示所有传递给函数的参数。

$@

与$*相同,但是略有区别,请查看Shell特殊变量。

$?

函数的返回值。

十五,输入输出重定向

Unix 命令默认从标准输入设备(stdin)获取输入,将结果输出到标准输出设备(stdout)显示。一般情况下,标准输入设备就是键盘,标准输出设备就是终端,即显示器。

输出重定向

  命令的输出不仅可以是显示器,还可以很容易的转移向到文件,这被称为输出重定向。   命令输出重定向的语法为:

代码语言:javascript
复制
$ command > file

  这样,输出到显示器的内容就可以被重定向到文件。   例如,下面的命令在显示器上不会看到任何输出:

代码语言:javascript
复制
$ who > users

  打开 users 文件,可以看到下面的内容:

代码语言:javascript
复制
$ cat users
oko         tty01   Sep 12 07:30
ai          tty15   Sep 12 13:32
ruth        tty21   Sep 12 10:10
pat         tty24   Sep 12 13:07
steve       tty25   Sep 12 13:03$

  输出重定向会覆盖文件内容,请看下面的例子:

代码语言:javascript
复制
$ echo line 1 > users
$ cat users
line 1

  如果不希望文件内容被覆盖,可以使用 >> 追加到文件末尾,例如:

代码语言:javascript
复制
$ echo line 2 >> users
$ cat users
line 1
line 2

输入重定向

  和输出重定向一样,Unix 命令也可以从文件获取输入,语法为:

代码语言:javascript
复制
command < file

  这样,本来需要从键盘获取输入的命令会转移到文件读取内容。   注意:输出重定向是大于号(>),输入重定向是小于号(<)。   例如,计算 users 文件中的行数,可以使用下面的命令:

代码语言:javascript
复制
$ wc -l users2 users

  也可以将输入重定向到 users 文件:

代码语言:javascript
复制
$ wc -l < users2$

注意:上面两个例子的结果不同:第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容。

重定向深入讲解

  一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:

  • 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
  • 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
  • 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。

  默认情况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。   如果希望 stderr 重定向到 file,可以这样写:

代码语言:javascript
复制
$command 2 > file

  如果希望 stderr 追加到 file 文件末尾,可以这样写:

代码语言:javascript
复制
$command 2 >> file

  2 表示标准错误文件(stderr)。   如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写:

代码语言:javascript
复制
$command > file 2>&1

  或

代码语言:javascript
复制
$command >> file 2>&1

  如果希望对 stdin 和 stdout 都重定向,可以这样写:

代码语言:javascript
复制
$command < file1 >file2

  command 命令将 stdin 重定向到 file1,将 stdout 重定向到 file2。

命令

说明

command > file

将输出重定向到 file。

command < file

将输入重定向到 file。

command >> file

将输出以追加的方式重定向到 file。

n > file

将文件描述符为 n 的文件重定向到 file。

n >> file

将文件描述符为 n 的文件以追加的方式重定向到 file。

n >& m

将输出文件 m 和 n 合并。

n <& m

将输入文件 m 和 n 合并。

<< tag

将开始标记 tag 和结束标记 tag 之间的内容作为输入。

Here Document

  Here Document 目前没有统一的翻译,这里暂译为”嵌入文档“。Here Document 是 Shell 中的一种特殊的重定向方式,它的基本的形式如下:

  1. command << delimiter
  2. document
  3. delimiter

  它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command。   注意:

  • 结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。
  • 开始的delimiter前后的空格会被忽略掉。

  下面的例子,通过 wc -l 命令计算 document 的行数:

代码语言:javascript
复制
$wc -l << EOF
    This is a simple lookup program    for good (and bad) restaurants    in Cape Town.
EOF
3
$

  也可以 将 Here Document 用在脚本中,例如:

代码语言:javascript
复制
#!/bin/bash
cat << EOF
This is a simple lookup program
for good (and bad) restaurants
in Cape Town.
EOF

  运行结果:

代码语言:javascript
复制
This is a simple lookup program
for good (and bad) restaurants
in Cape Town.

  下面的脚本通过 vi 编辑器将 document 保存到 test.txt 文件:

代码语言:javascript
复制
#!/bin/sh
filename=test.txt
vi $filename <<EndOfCommands
i
This file was created automatically from
a shell script
^[
ZZ
EndOfCommands

  运行脚本:

代码语言:javascript
复制
$ sh test.sh
Vim: Warning: Input is not from a terminal
$

打开 test.txt,可以看到下面的内容:

代码语言:javascript
复制
$ cat test.txt
This file was created automatically from
a shell script
$

/dev/null 文件

  如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:

代码语言:javascript
复制
$ command > /dev/null

  /dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到”禁止输出“的效果。   如果希望屏蔽 stdout 和 stderr,可以这样写:

代码语言:javascript
复制
$ command > /dev/null 2>&1

十六,文件包含

像其他语言一样,Shell 也可以包含外部脚本,将外部脚本的内容合并到当前脚本。

  Shell 中包含脚本可以使用:

代码语言:javascript
复制
. filename

  或

代码语言:javascript
复制
source filename

  两种方式的效果相同,简单起见,一般使用点号(.),但是注意点号(.)和文件名中间有一空格。   例如,创建两个脚本,一个是被调用脚本 subscript.sh,内容如下:

代码语言:javascript
复制
url="http://see.xidian.edu.cn/cpp/view/2738.html"

  一个是主文件 main.sh,内容如下:

代码语言:javascript
复制
#!/bin/bash
. ./subscript.sh
echo $url

  执行脚本:

代码语言:javascript
复制
$chomd +x main.sh
./main.sh
http://see.xidian.edu.cn/cpp/view/2738.html
$

  注意:被包含脚本不需要有执行权限。

文章参考出处:

http://www.cnblogs.com/maybe2030/

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-10-16,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 架构师小秘圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 单引号
  • 双引号
  • 拼接字符串
  • 获取字符串长度
  • 提取子字符串
  • 查找子字符串
  • 定义数组
  • 读取数组
  • 获取数组的长度
  • 显示转义字符
  • 显示变量
  • 显示换行
  • 显示不换行
  • 显示结果重定向至文件
  • 原样输出字符串
  • 显示命令执行结果
  • if ... else 语句
  • if ... else ... fi 语句
  • if ... elif ... fi 语句
  • break命令
  • continue命令
  • 输出重定向
  • 输入重定向
  • 重定向深入讲解
  • Here Document
  • /dev/null 文件
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com