跳到主要内容

Shell工具与脚本

Linux Shell

Linux Shell

Linux Shell 主要提供以下两种功能:

  • 解释用户在命令行提示符下输入的命令
  • 编写 Shell 脚本,实现高级管理功能

Shell 两种执行命令的方式:

  • 第一种,交互式。用户每输入一条命令,Shell 就解释执行一条
  • 第二种,批处理式。需要事先编写一个 Shell 脚本,其中包含若干条命令,让 shell 一次将这些命令执行完,编写 Shel 脚本的过程就是 Shell 编程

shell 脚本是解释执行的,不需要编译,shel 程序从脚本中一行一行读取并执行这些命令相当于一个用户把脚本中的命令一行一行敲到 shell提示符下执行。

Shell script

Shell 脚本是一个文本文件,shel 脚本编程无需编译器,也不需要集成开发环境,一般使用文本编辑器即可,首选的编辑器是 Vim 或 Emacs,在桌面环境中可直接使用图形化编辑器 gedit 或kate

Shel 脚本编写的“Hello world”:

sudo touch hello
sudo gedit hello
#!/bin/bash
echo "Hello World!"

注解:

  • “#!”指定 shell 脚本的运行环境, 声明该脚本使用哪个 shell 程序运行; 如果没有指定,则以当前正在执行的 shell 来解释执行
  • 以“#”开头的行是注释行,shell 在执行时会忽略“#”之后的所有内容
  • echo 命令用来显示字符串信息

举例:编写上述 hello的 Shell 脚本,执行脚本:

./hello
  • 执行脚本命令时在脚本文件名前加上了”./”,表明启动当前目录下的脚本文件 hello
  • 如果直接执行脚本文件 helo,Linux 系统会到命令搜索路径(PATH)中去查找该脚本文件,由于此例脚本位于用户主目录,会提示指定文件不存在

可以在指定的 shell 下执行脚本,以脚本名作为参数。基本用法如下:

Shell 名称 脚本名[参数]

举例:执行 hello 脚本

$ bash ./hello# 使用bash
$ sh ./hello#使用sh

将输入重定向到 Shell 脚本

Shell variables

Linux 的 Shell 编程支持以下3种变量类型:(1)用户自定义变量、(2)环境变量、(3)系统变量

  1. 用户自定义变量

编写 Shell 脚本时定义的变量,可在 Shell 程序内任意使用和修改,可看作局部变量,仅在当前 shell 实例中有效

变量定义:在 she 编程中,变量是非类型性质的,不必指定变量是数字,还是字符串,给变量赋值的过程也就是定 义一个变量的过程,其格式如下: 变量名=值

  • 备注:在赋值符号两边不允许有空格。如果值中含有空格、制表符或换行符,则要将这个字符串用引号括起来
  • 在同一个变量中,可以一次存放整型值,下一次再存储字符串 举例:
x=8
x="Hello"

变量名的命名应当遵循如下规则:

  • 首个字符必须为字母(az AZ)
  • 中间不能有空格,可以使用下画线(_).
  • 不能使用标点符号.
  • 不能使用 Shell 中的关键字(在 bash 中可用 help 命令查看保留关键字)

删除变量:使用 unset 命令可以删除变量,语法如下:

unset 变量名 举例:

unset x

变量引用:

  • 如果要引用变量值,可以在变量名前面加一个美元符号“$”。例如变量名为myName,使用$myName 就可以引用该变量

变量显示:

  • 通常使用函数 echo 来显示变量,例如:
# 将一个字符串赋值给变量 hello
$ hello=" Hello World!"
# 显示变量 hello 的值:
$ echo $hello

通过

echo $PATH

可以查看 PTAH 变量的路径

  1. 环境变量

Linux 中环境变量包括 系统级 和 用户级,系统级的环境变量是每个登录到系统的用户都要读取的系统变量,用户级的环境变量则是该用户使用系统时加载的环境变量。为了与普通变量进行区分,通常将环境变量名设为大写

系统级:

  • /etc/environment:Linux 系统在登录时读取的第一个文件,用于为所有进程设置环境变量。系统使用此文件时并不是执行此文件中的命令,而是根据 KEY=VALUE 模式的代码,对 KEY 赋值以 VALUE。文件中如果要定义 PATH 环境变量,只需加入一行形如 PATH=$PATH:/xxx/bin 的代码即可
  • /etc/profile:Linux 系统登录时执行的第二个文件,可以用于设定针对全系统所有用户的环境变量。该文件一般是调用 /etc/bash.bashrc 文件
  • /etc/bash.bashrc:系统级的 bashrc文件, 为每一个运行 bash shell 的用户执行此文件。此文件会在用户每次打开 shel 时执行一次

注意:/etc/environment 是设置整个系统的环境,而/etc/profile 是设置所有用户的环境前者与登录用户无关,后者与登录用户有关。这两个文件修改后一般都要重启系统才能生效

用户级:

  • ~/.profile:对应当前登录用户的 profile 文件,用于定制当前用户的个人工作环境。每个用户都可使用该文件输入专用于自己使用的 shel 信息。当用户登录时,该文件仅仅执行一次。默认情况下,其设置一些环境变量,执行用户的.bashrc 文件
  • ~/.bashrc:对应当前登录用户的 bash 初始化文件,当用户每次打开 shell 时,系统都会执行此文件一次。ROS使用过程中要设置此文件配置环境变量
  • bashrc文件注解:Linux 系统中很多 shell,包括bash,sh,zsh,dash和 korn 等,不管哪种shel 都会有一个 .bashrc 的隐藏文件,它就相当于 shell 的配置文件。主要保存用户自定义环境变量、个性化设置信息等

根据以上描述,这几个文件的执行先后顺序应当是:

  1. /etc/enviroment->/etc/profile ->/etc/bash.bashrc
  2. ~/.profile ->~/.bashrc

配置环境变量:

  1. 在 Linux 下设定环境变量时,如果只是临时用一下,可以直接在 shell 下用 set 或 export 命令设定环境变量。该操作只能在当前 shell 脚本下可用,切换到另一个终端就会失效,举例:
export PYTHONPATH=/home/yanting/learning/ssd-caffe/python
  1. 如果希望此环境变量每次开机或打开 shell 时自动设定而无须每次都手动设定,那么需要将export 命令写入以上的系统文件中,举例:
$ sudo gedit ~/.bashrc
$ export PYTHONPATH=/home/yanting/learning/caffe/python:$PYTHONPATH
$ source ~/.bashrc
# PATH采用:来分隔,冒号左右不需要空格;$PYTHONPATH表示变量引用
  1. 系统变量 Linux 系统变量是系统为了正常执行命令,维持正常运转而自带的变量,常用大写字母表示,常见的Linux 环境变量如下:
变量名作用
HOME表示当前用户的家目录
SHELL表示当前用户的shell解释器
LANG表示系统的语言
RANDOM调用该变量可以由系统生成一个随机数字
PATH定义Shell解释器搜索命令的路径

Redirection and pipe

Redirection

stdin, stdout和stderr:

在Linux下,当一个用户进程被创建时,系统会自动为该进程创建三个数据流,即:stdin,stdout和 stderr

  1. 三个数据流默认是表现在用户终端上,执行一个 shel 命令行时通常会自动打开三个标准文件
  • 标准输入文件(stdin),通常对应键盘
  • 标准输出文件(stdout)和 标准错误输出文件(stderr),这两个文件都对应屏幕
  1. 作用: 将从标准输入文件中得到输入数据,正常输出数据输出到标准输出文件,将错误信息输出到标准错误文件中

  2. 存在问题:

  • 输入数据从键盘输入时,输入的数据只能用一次,且输入有误修改起来不方便
  • 输出到屏幕上的信息只能看不能修改,无法对此输出作更多处理

输入/输出重定向:

为了解决上述问题,Linux 系统为输入、输出的传送引入了另外两种机制,即 输入/输出重定向管道

(1) 输入重定向: 把命令(或可执行程序)的标准输入重定向到指定的文件中。也就是说,输入不来自键盘,而来自一个指定的文件

  • 命令<文件,表示将指定文件作为命令的输入
  • 命令<<分界符,表示从标准输入文件(键盘)中读入,直到遇到分界符才停止(读入的数据不包括分界符)这里的分界符是自走义的字符串
  • 备注:许多命令都支持输入重定向,此处使用命令指代各个支持输入重定向的命令
  • 几个基本符号及其含义:0 表示stdin标准输入;1 表示stdout标准输出;2 表示stderr标准错误

举例1: 默认情况下,cat 命令会接受标准输入文件(键盘)的输入,并显示到标准输出(屏幕)。但如果用文件代替键盘作为标准输入,那么该命令会以指定的文件作为输入,并将文件中的内容读取并显示到屏幕

cat hello
#! /bin/bash
# 显示"Hello World!
echo "Hello World!"

举例2:输入 cat 命令后回车,cat 命令会默认捕获键盘的输入,并将捕获到的内容直接输出到屏幕(使用ctrl+c停止捕获)

cat
ubuntu
ros
C++
ros

输入更改为 cat << aaa,cat 命令依旧会捕获键盘的输入的显示在屏幕上

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

  • 命令>文件,将命令执行的标准输出结果重定向输出到指定的文件中,如果该文件已包含数据,会清空原有数据,再写入新数据
  • 命令2>文件,将命令执行的错误输出结果重定向到指定的文件中,如果该文件中已包含数据,会清空原有数据,再写入新数据
  • 命令>>文件,将命令执行的标准输出结果重定向输出到指定的文件中,如果该文件已包含数据,新数据将追加入到原有内容的后面
  • 命令2>>文件,将命令执行的错误输出结果重定向到指定的文件中,如果该文件中已包含数据,新数据将追加^到原有内容的后面

举例:新建一个包含有"Linux"字符串的文本文件 Linux.txt,以及空文本文件 demo.txt,执行如下命令:

cat b.txt >demo.txt
$ cat: b.txt: No such file or directory <-- 错误输出信息依然输出到了显示器中
cat b.txt 2>demo.txt
cat demo.txt
cat: b.txt: No such file or directory
$ cat b.txt 2>>demo.txt
$ cat aemo.txt
$ cat: b.txt: No such file or directory$ cat: b.txt: No such file or directory<--追加写入错误输出信息

Pipe

管道: 管道是一种通信机制,通常用于进程间的通信。它表现出来的形式是将前面每一个进程的输出(stdout)直接作为下一个进程的输入(stdin)

管道又分为 匿名管道具名管道,我们在使用过滤程序时经常会用到匿名管道,在命令行中由“|”分隔符表示,其语法格式为:

command1|command2 command1|command2[|commandN...]

  • 当在两个命令之间设置管道时,管道符|左边命令的输出就变成了右边命令的输入
  • 只要第一个命令向标准输出写入,第二个命令是从标准输入读取,那么这两个命令就可以形成一个管道
  • 管道可以和重定向连用
注意
  1. 创建一个名为 "ROS" 的目录, 并在该目录下创建三个文件 file1 、 file2 和 file3 。
  2. 使用命令行在当前目录下查看文件列表,并将文件列表保存到一个名为 "filelist.txt" 的文件中。
  3. 在当前目录下创建一个名为 "backup" 的目录,并将 ROS 目录下的所有文件复制到 backup 目录中。
  4. 使用命令行将 file1 重命名为 newfile , 并在 newfile 所在的目录下创建一个名为 "log.txt" 的空文件。
  5. 删除 file2 和 file3 两个文件, 同时删除 backup 目录及其下的所有文件。
  6. 在当前目录下创建一个名为 "script.sh" 的 shell 脚本文件, 并在其中编写一个简单的脚本来输出当前系统的日期和时间。
  7. 执行 script.sh 脚本, 并将输出结果保存到名为 "output.txt" 的文件中。
  8. 使用 gedit 编辑器打开 output.txt 文件, 并在文件末尾添加一行文字 "End of output" 。
  9. 在当前目录下创建一个名为 "ROSdir" 的目录,并在该目录下创建两个子目录 "dir1" 和 "dir2" 。
  10. 将当前目录下的脚本文件 script.sh 复制到 dir1 目录中, 并将 output.txt 文件复制到 dir2 日录中。
示例