shell编程理论

#! – 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序。(#!/bin/bash)

  • 运行 Shell 脚本有两种方法
    • 作为可执行程序
      chmod +x ./test.sh  #使脚本具有执行权限
      ./test.sh  #执行脚本
      注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,
      linux 系统会去 PATH 里寻找有没有叫 test.sh 的,
      而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,
      你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找。
      
    • 作为解释器参数
      这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名,如:
      /bin/sh test.sh
      这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。
      

source命令用法

source FileName
作用:在当前 bash 环境下读取并执行 FileName 中的命令。该 filename 文件可以无 "执行权限"。

注:该命令通常用命令 . 来替代。

sh、bash的命令用法:

  sh FileName 或 bash FileName
  作用:打开一个子 shell 来读取并执行 FileName 中命令。该 filename 文件可以无 "执行权限"。
  注:运行一个shell脚本时会启动另一个命令解释器。

./ 的命令用法:

  ./FileName
  作用: 打开一个子 shell 来读取并执行 FileName 中命令,该 filename 文件需要 "执行权限"。
  注:运行一个 shell 脚本时会启动另一个命令解释器。

fork、source、exec

- 使用fork方式运行script时, 就是让shell(parent process)产生一个child process去执行 该script,
当child process结束后,会返回parent process,但parent process的环境是 不会因child process的改变而改变的。
- 使用source方式运行script时, 就是让script在当前process内执行, 而不是产生一个 child process来执行。
由于所有执行结果均于当前process内完成,若script的环境有所改变, 当然也会改变当前process环境了。
- 使用exec方式运行script时, 它和source一样,也是让script在当前process内执行,但是process内的原代码剩下部分将被终止。
同样,process内的环境随script改变而改变。
通常如果我们执行时,都是默认为fork的。

参数说明

我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n 代表一个数字, $0 为执行的文件名;$1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……

参数处理	         说明
$#	     传递到脚本的参数个数
$*       以一个单字符串显示所有向脚本传递的参数。 如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$$	     脚本运行的当前进程ID号
$!	     后台运行的最后一个进程的ID号
$@	     与$*相同,但是使用时加引号,并在引号中返回每个参数。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$-	     显示Shell使用的当前选项,与set命令功能相同。
$?	     显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。            

  $* 与 $@ 区别:
  相同点:都是引用所有参数。
  不同点:只有在双引号中体现出来。
  假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。

test.sh para1 para2 para3
$0       $1    $2     $3
$0是脚本名称,$1,2是参数;
$# 参数个数
  

输入/输出重定向

  • 在 Linux 中,所有的内容都是文件,计算机硬件也是文件,标准输入设备(键盘)和标准输出设备(显示器)也是文件
  • Linux 是使用设备文件名来表示硬件的(比如 /dev/sda1 就代表第一块 SATA 硬盘的第一个主分区), 但是键盘和显示器的设备文件名并不好记忆,我们用”0”、”1”、”2”来分别代表标准输入、标准输出和标准错误输出
  • 输出重定向指的是改变输出方向,不再输出到屏幕上,而是输出到文件他设备中 输入重定向则是指不再使用键盘作为输入设备,而是把文件的内容作为命令的输入
设 备	设备文件名	文件描述符	类 型
键盘	/dev/stdin	        0	标准输入
显示器	/dev/stdout	       1	标准输出
显示器	/dev/stderr	       2	标准错误输出

命令	               说明
command > file	  把命令的正确输出重定向到 file。
command < file	  将输入重定向到 file。
command >> file	  将输出以追加的方式重定向到 file。
错误命令 2 > file   以覆盖的方式,把命令的错误输出输出到指定的文件或设备中
错误命令 2 >> file   以追加的方式,把命令的错误输出输出到指定的文件或设备中
command &> file	  =command > file 2>&1 以覆盖的方式,把正确输出和错误输出都保存到同一个文件中
command &>> file	=command >> file 2>&1 以追加的方式,把正确输出和错误输出都保存到同一个文件中
command > filename 2>errfilename  把正确输出和错误输出分别保存到不同文件中
n > file	        将文件描述符为 n 的文件重定向到 file。
n >> file	        将文件描述符为 n 的文件以追加的方式重定向到 file。
n >& m	          将输出文件 m 和 n 合并。
n <& m	          将输入文件 m 和 n 合并。
<< tag	          将开始标记 tag 和结束标记 tag 之间的内容作为输入。
需要注意的是文件描述符 0 通常是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)
如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写:
$ command > file 2>&1
或者  $ command >> file 2>&1

如果希望对 stdin 和 stdout 都重定向,可以这样写:
$ command < file1 >file2


Here Document

Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序。                 
  它的基本的形式如下:                       
  command << delimiter
      document
  delimiter

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

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

/dev/null 文件

如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:
  $ command > /dev/null
  /dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。
  但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。
  如果希望屏蔽 stdout 和 stderr,可以这样写:  
  $ command > /dev/null 2>&1

  必须是2>&1,如果改成1>&2,仍然是标准输出;

su

su name: 使用nologin shell 执行/etc/bashrc,~/.bashrc
su - name 使用login shell 执行/etc/profile ,/etc/bashrc,/etc/.bash_profile ~/.bashrc

()

(cmd) 表示在子shell中执行;cmd是在当前shell中执行;
当前shell中定义的变量,子shell读不到;

`` vs $()

``和$():功能相同,优先执行包含的命令