[Shell] [笔记]UNIX/Linux/OSX中的Shell编程

全面介绍UNIX/Linux/OSX中Shell编程的基础知识,涵盖文件操作、目录管理、正则表达式、命令解析、变量处理、环境控制及常用命令。深入探讨Shell语法、流程控制结构和函数编写技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

UNIX/Linux/OSX中的Shell编程(第4版)

Stephen G. Kochan Patrick Wood著

基础

1. 使用文件

  • UNIX系统只识别三种基本类型文件:普通文件(系统中包含数据、文本、程序指令或其它内容的文件)、目录文件和特殊文件(对UNIX有特殊意义,通常和某种形式的I/O相关联)

  • 文件名字符数不能超过255个

2. 使用目录

  • 登录系统后,自动处于个人主目录中
  • 以"/“起始的路径名为绝对路径名,不以”/"开头的路径为相对路径,相对于当前工作目录
  • "…“指向当前目录的上一级目录,”."引用当前目录

3. 文件名替换

*
echo *
#部分替换,限制匹配
echo chap*
? 或 []

匹配单个字符

echo a?
# 列出以小写字母开头且不易数字结尾的所有文件
ls [a-z]*[!0-9]
[!chars]

不在chars中的任意单个字符

4. 文件名中的空格

两种解决方法:

  • 放在引号中
cat "my test document"
  • 使用反斜杠转义
cat my\ test\ document

5. 标准输入/输出和I/O重定向

  • Ctrl+d终结标准输入
  • 输出重定向
# 内容覆盖
who > users

# 追加形式
echo line 2 >> users
  • 输入重定向
wc -l < users

I/O重定向

写法含义
< file标准输入重定向到file
> file标准输出重定向到file
>| file标准输出重定向到file,file内容清空
>> file追加
<< word标准输入重定向到随后的行中,知道某行只包含了word
<& digit标准输入重定向到与文件描述符digit相关联的文件
>& digit标准输出重定向到与文件描述符digit相关联的文件
<&-关闭标准输入
>&-关闭标准输出
<> file打开file进行读取和写入
  • file上不会执行文件名替换
  • 行内输入重定向
    • 为了不让Shell解释输入行中的内容,可以在文档结尾单词前使用反斜线:
      $ cat <<\FOOBAR
      > \\\
      > `date`
      > $HOME
      > FOOBAR
      \\\
      `date`
      $HOME
      
    • 如果>>后面的第一个字是连接符-,那么输入中的其拿到制表符都会被Shell删除

6. 标准错误

  • 默认同终端或终端程序相关联

  • 即使标准输出被重定向到文件中,错误小心仍然显示到终端

  • command 2> file 将标准错误重定向到文件中

  • 另一种写法用于确保所有的错误信息都出现在终端,哪怕监本已经将其输出重定向了文件或管道:echo "Error message" 1>&2(将应该输出到文件描述符#1的错误信息重定向到文件描述符#2)

7. 管道

过滤器:从标准输入读取数据,将结果写入标准输出

# wc为过滤器,cat/sort都可以作为过滤器
# who/date/cd/pwd/echo/rm/mv/cp都不算
who | wc -l

8. Shell

  • 只要系统允许用户登录,UNIX系统(init程序)就会在每个终端端口自动启动一个getty程序,getty是一个设备驱动程序,能够让login程序在其所分配的终端上显示login:等待用户输入

  • login比对/etc/passwd中的条目验证登录名密码,/etc/passwd中有验证成功后要启动的程序(每行最后一个冒号后面),没有就默认使用标准Shell,即/bin/sh

  • 登录Shell会在系统中查找并读取两个特殊文件:/etc/profile会检查新邮件、默认的文件创建掩码、建立默认PATH及其它管理员希望登录完成的工作;.profile位于用户主目录下,其对环境做出的修改会一直持续到登出Shell

  • Shell的职责:解释型编程语言、程序执行、变量及文件名替换、I/O重定向、管道、环境控制

    • Shell首先进行变量和文件名替换,查找文件名替换字符*、?或[…]

    • Shell在磁盘搜索命令之前,会先判断是否为内建命令(cd/pwd/echo)

    • I/O重定向:wc程序在wc -l < users中只接收了-l一个参数,他会转而去统计标准输入的内容,Shell会将其的标准输入重定向为文件users

    • 管道:将上一个命令的标准输出连接到下一个命令的标准输入,然后执行两者

    • 环境控制:能够定制个人环境

    • 解释型:Shell有自己的内建语言,这种语言是解释型的,Shell会分析所遇到的每一条语句,然后执行所发现的有效的命令

  • Shell先进行管道和I/O重定向,然后是变量替换、命令替换,再是文件名替换,接着将命令行解析成参数,Shell会从命令行中删除空格、制表符和换行符(空白字符),然后切分成参数交给所请求的命令

  • Shell的命令搜索次序

    • 首先检查命令是否为保留字(如for或do)
    • 如果不是保留字,也没有引用,接着检查别名列表,如果在其中找到匹配的别名,就执行替换操作,**如果别名定义是以空格结尾,Shell还会尝试对下一个单词执行别名替换。**针对替换后的最终结果,再次检查保留字列表,如果不是保留字,继续进行第3步
    • 针对命令名检查函数列表,如果找到,执行其中的同名函数
    • 检查是否为内建命令(如cd和pwd)
    • 最后,搜索PATH来定位命令
    • 如果还没找到,输出错误信息command not found

9. 正则表达式

记法含义例子
.匹配任意字符(Shell则认为?能匹配任意单个字符)a…
^匹配行首^wood
$匹配行尾x$
*重复之前的正则表达式零次或多次xx* (一个或多个连续x)
+重复之前的正则表达式一次或多次xx+ (两个或多个连续x)
[chars]匹配chars中的任意字符[a-z] (小写字母)
[^chars]匹配不在chars中的任意字符[^0-9] (非数字字符)
\{min, max\}重复之前的正则表达式至少min次,至多max次[0-9]\{3, 9\} (连续3-9个数字)
\(…\)将括号中保存下来的字符保存到接下来的寄存器中(1-9)^\(.\)\1 (行首前两个相同的字符)

10. 常用字符的八进制形式

字符八进制值
响铃Bell7
退格Backspace10
制表符Tab11
回车换行Newline12
换行Linefeed12
换页Formfeed14
回车Carriage Return15
取消Escape33

11. 退出状态

  • 退出码为0表示程序运行成功
  • 对于管道而言,退出状态对应的是管道中的最后一个命令
  • 对于文件复制命令cp,可能的错误情况是1(文件没找到)、2(文件不可读)、3(目标目录没找到)、4(目标目录不可写)、5(一般性错误)

12. 波浪符替换

  • Shell会检查命令行中的每一个单词及变量是否以未引用的开头,如果是,将单词或变量中其余直到/的部分视为登录名,并在系统文件/etc/passwd中查找该用户。如果存在,使用其主目录替换以及登录名。如果不存在,不做任何修改
  • 单独的或/之后的会被HOME变量替换

Tips

  1. 一行中输入多个命令,使用;分隔

  2. 向后台发送命令:

# 返回[job number] PID
$ sort bigdata > out &
[1] 1258
  1. chmod +x <file> 使文件具有可执行权限

  2. 没有参数的echo会产生一个空行

  3. 不想看到命令结果,可以将输出重定向到系统的垃圾桶:/dev/null,任何写入这个文件的东西都会消失!

    要强制写入或从终端读取,可以利用/dev/tty,该文件总是指向终端程序

  4. 调试:sh -x跟踪执行过程,这启动了一个-x选项的新shell执行指定程序,命令在执行的同时打印到终端,前面加了一个+。

  5. Shell的两个特殊操作符:&&||,根据之前命令成功与否来执行后续的命令

  6. 如果文件中的第一行的前两个字符是#!,那么该行余下的部分指定了该文件的解释器:#!/bin/bash

命令

1. date

显示日期和时间

$ date
Thu Dec 27 19:31:25 CST 2018

2. who

获取当前已登录到系统中所有用户信息
用户ID、用户所在的tty编号(UNIX系统为用户所在终端或网络设备分配的唯一标识数字)、登录时间

$ who
root     pts/0        2018-12-27 19:41 (10.131.253.92)

[root@CENTOS-MINION-2 ~]# who am i
root     pts/0        2018-12-27 19:41 (10.131.253.92)

3. echo

  • 回显字符,压缩单词间多余的空白字符;
$ echo one    two       three
one two three
  • 会自动在最后一个参数后面加上一个用于终止的换行符,可以在最后加上转义字符\c不输出换行符(\c是由echo解释的,而非Shell,必须将其引用起来交给echo),有的系统不会显示这些echo转义字符

echo命令的转义字符

字符输出
\b退格
\c忽略输出中最后的换行符
\f换页
\n回车换行
\r回车
\t制表符
\\反斜线
\0nnnASCII值为nnn的字符,nnn是1-3位的八进制数

4. ls

列举文件;

-C强制以多列形式输出

-l 输出文件详细信息:

  • total:文件占用的存储块(1024字节)数
  • 文件类型:d为目录,-为文件,特殊文件是b/c/l/p
  • 访问权限:文件所有者、与文件所有者同组的其他用户、系统其他用户
  • 链接数
  • 文件所有者
  • 文件所属组
  • 文件大小
  • 文件最后的修改时间
$ ls
anaconda-ks.cfg
apache-maven-3.5.2-bin.tar.gz
docker-ce-17.03.2.ce-1.el7.centos.x86_64.rpm
docker-ce-selinux-17.03.2.ce-1.el7.centos.noarch.rpm
get-pip.py
go1.9.2.linux-amd64.tar.gz
jdk-8u131-linux-x64.tar.gz
nohup.out
openscap_data
privoxy-3.0.26-stable
privoxy-3.0.26-stable-src.tar.gz

$ls -l
total 314124
-rw-------.  1 root root      1089 Aug 10  2016 anaconda-ks.cfg
-rw-r--r--.  1 root root   8738691 Apr 12  2018 apache-maven-3.5.2-bin.tar.gz
-rw-r--r--.  1 root root  19529520 Apr 12  2018 docker-ce-17.03.2.ce-1.el7.cento                                                                                        s.x86_64.rpm
-rw-r--r--.  1 root root     29108 Apr 12  2018 docker-ce-selinux-17.03.2.ce-1.e                                                                                        l7.centos.noarch.rpm
-rw-r--r--.  1 root root   1780465 Apr 13  2018 get-pip.py
-rw-r--r--.  1 root root 104247844 Apr 12  2018 go1.9.2.linux-amd64.tar.gz
-rw-r--r--.  1 root root 185540433 Apr 12  2018 jdk-8u131-linux-x64.tar.gz
-rw-------.  1 root root     28908 Nov 30 11:01 nohup.out
drwxr-xr-x.  2 root root        39 Aug 10  2016 openscap_data
drwxr-xr-x. 10 root root      4096 Apr 13  2018 privoxy-3.0.26-stable
-rw-r--r--.  1 root root   1741772 Aug 27  2016 privoxy-3.0.26-stable-src.tar.gz

5. cat

(concatenate)显示文件内容

$cat dingtest
if (( i == 100 ))
then
  echo "$i == 100"
else
  echo "$i != 100"
fi

如果没有指定参数,$*为空,cat也接受不到任何参数,这会使它从标准输入中读取

cat $* |
while read line
do
    echo "$line"
done

6. wc

统计行数、单词数、字符数;命令选项必须出现在文件名参数之前

$wc dingtest
 6 17 69 dingtest
 
$wc -l dingtest
6 dingtest

$wc -w dingtest
17 dingtest

$wc -c dingtest
69 dingtest

7. cp

复制文件,saved_names如果存在会被覆盖

$cp names saved_names

# 将文件collect从目录../programs复制到当前目录中
$cp ../programs/collect .

8. mv

文件重命名,hold_it如果存在会被覆盖;
在目录间移动文件

$ mv saved_names hold_it

#将三个文件移动到../misc目录中
$ mv wb collect mon ../misc

9. rm

删除文件

$ rm hold_it
  • -f忽略不存在的文件,强制删除,不给出提示。

  • -r 指示rm将参数中列出的全部目录和子目录均递归地删除。

  • -i进行交互式删除。因为一旦文件被删除,它是不能被恢复的。为了防止这种情况的发生,可以使用“i”选项来逐个确认要删除的文件。如果用户输入“y”,文件将被删除。

  • rm -r <dir>删除指定目录和其中的所有文件(如果没有使用- r选项,则rm不会删除目录。 )

  • rm -rf *删除当前目录下的所有文件

10. pwd

显示工作目录

$pwd
/ding

11. cd

更改目录,参数-表示上一个目录,无参数表示回到HOME目录

12. mkdir

创建目录

13. rmdir

删除目录,要先删除目录中包含的所有文件,否则会报错;

14. ln

文件链接,一个文件有连个不同的名字,不会占用两倍磁盘空间;

对于普通链接,被链接的文件必须与链接文件处于同一个文件系统中,否则会报错;

可以随意删除两个连接文件中的任何一个,另外一个不会因此消失

$ ln wb writeback
$ ls -l
...
-rwxr-xr-x 2 steve DP3822 89 JUL 20 15:22 wb
-rwxr-xr-x 2 steve DP3822 89 JUL 20 15:22 writeback

要在不同文件系统的文件之间创建链接,使用-s选项,这叫做符号链接(ls -l文件类型为l),指向原始文件;

例子中文件大小为15,内容其实就是字符串/users/steve/wb;

如果原始文件被删除,符号链接无效,但符号链接本身不会删除->悬挂符号链接;

  • -Ll获得符号链接所指向文件的详细信息
$ ln -s /users/steve/wb ./symwb
$ ls -l
...
lrwxr-xr-x 1 pat DP3822 15 JUL 20 15:22 symb -> /users/steve/wb

$ ls -Ll
...
-rwxr-xr-x 2 steve DP3725 15 JUL 20 13:30 wb

为特定目标目录中的多个文件创建链接:

ln <files> <directory>

15. ps

给出系统中所运行进程的信息:PID、TTY、进程所使用的计算机时间、进程名称;

  • -f打印更多信息:PPID(父进程ID)、进程开始时间
$ ps
  PID TTY          TIME CMD
 4581 pts/0    00:00:00 bash
 9255 pts/0    00:00:00 ps
 
$ ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
root      4581  3875  0 19:56 pts/0    00:00:00 -bash
root     10717  4581  0 21:38 pts/0    00:00:00 ps -f

16. cut

从每行内提取字段:cut -cchars file

  • -d指定字段分隔符;
  • -f指定待提取的字段
# 提取前8个字符
$ who | cut -c1-8 

# 提取前8个字符,然后提取第18个到行尾的字符
$ who | cut -c1-8,18-

# 从/etc/passwd文件中提取每行的由:分割的第1和6字段
$ cut -d: -f1,6 /etc/passwd 

17. paste

将文件中每行合并在一起,由制表符分隔

  • -d指定分隔符;
  • -s将同一个文件中的所有行合并到一起,默认制表符分隔
$ paste names numbers
Tony    123456
Emanuel 55555

# 粘贴ls命令的输出(paste将来自标准输入`-`的所有行进行合并),使用空格作为分隔符
$ ls | paste -d' ' -s -

18. tr

过滤器,转换标准输入中的字符;从标准输入获得输入,结果写入标准输出,不改动原始文件

  • -s压缩多次连续出现的字符;
  • -d删除输入流中的个别字符
# 将:换成制表符,11为制表符的八进制值
tr : '\11'

# 小写换成大写,加引号避免Shell将其解释为模式
tr '[a-z]' '[A-Z]' < intro

# 大写转小写,小写转大写
tr '[a-zA-Z]' '[A-Za-z]' 

# A-M转成N-Z,N-Z转成A-M
tr '[A-Z]' '[N-ZA-M]' 

# 所有:转成制表符,使用单个制表符替代多个制表符
tr -s ':' '\11'

# 删除换页符
tr -d '\14' 

19. grep

在一个或多个文件中搜索指定的模式

  • -i忽略大小写;
  • -v获得不匹配的行;
  • -l得到匹配指定模式的行所在的文件;
  • -n显示行号
# 在当前目录的所有文件中搜索单词shell
grep shell *

# *放在单引号中避免Shell误解
grep '*' stars

20. sort

字母顺序排序,特殊字符按内部编码排序,空格32,双引号34

  • -u消除重复行
  • -r逆序排列
  • -o指定输出文件
  • -n将行中第一个字段视为数字,对应的数据进行算数排序
  • sort -k2 <file>从第2个字段开始排序
  • -t后的字符被视为分隔符,sort -k3n -t: /etc/passwd对第3个以冒号分隔的字段进行算数排序

21. uniq

uniq in_file (out_file)查找或删除重复行(连续出现的重复行,所以一般需要先sort才能被判断为重复),可做过滤器

  • -d只把重复的行写入输出
  • -c统计出现的次数
sort names | uniq

sort names |uniq -d

# 找出数据文件中词频最高的单词
tr '[A-Z]' '[a-z]' datafile | sort | uniq -c | head

22. expr

数学等式解算器,操作数和操作符之间必须用空格分隔!!!

  • :操作符,针对出现在第二个操作数中的正则表达式匹配第一个操作数中的字符,默认返回匹配到的字符数
$ expr $i + 1
1

$  expr "$file" : ".*"
0

23. shift

向左移动位置参数,同时,$#的值也会自动减1;

  • 如果$#已经为0的情况下使用shift,会发出错误信息:prog: shift: bad numberprog是执行不当的shift命令的程序名)

  • shift 3:一次移动3个位置

24. test

测试单个或多个条件

  • test命令的所有操作数和操作符必须是独立的,用空白字符分隔的!

  • 将test的参数放在双引号中是一种良好的编程实践

# test命令的所有操作数和操作符必须是独立的,用空白字符分隔的
4 test "$name" = julio

$ test 1 = 1
$ echo $?
0

# =的优先级高于-z,所以test会将命令作为等量关系测试来处理,希望在=之后还有一个参数,所以报了错
$ symbol==
$ test -z "$symbol"
$ echo $?
1
# 下面的写法可以防止这种情况发生
$ test X"$symbol" = X
  • test的另一种格式:[ express ]

    • express两边与[]之间必须有空格
    $ [ -z "" ]
    $ echo $?
    0
    
  • test字符串操作符

操作符如果满足下列条件,则退出码为0
string1 = string2string1等于string2
string1 != string2string1不等于string2
stringstring不为空
-n stringstring不为空
-z stringstring为空
  • test整数操作符
操作符如果满足下列条件,则退出码为0
int1 -eq int2int1等于int2
int1 -ge int2int1大于等于int2
int1 -gt int2int1大于int2
int1 -le int2int1小于等于int2
int1 -lt int2int1小于int2
int1 -ne int2int1不等于int2

在使用整数操作符时,将变量的值视为整数的是test命令,而不是Shell

  • test文件操作符
操作符如果满足下列条件,则退出码为0
-d filefile是一个目录
-e filefile存在
-f filefile是一个普通文件
-r file可由进程读取
-s file不是空文件
-w file可由进程写入
-x file可执行
-L file是一个符号链接
  • 逻辑否定操作符![ ! -r /users/steve/phonebook ]

  • 逻辑“与”操作符-a[ ! -f "$file" -a $(who > $file) ],(如果-f测试没有通过,就不会执行who命令)

  • 逻辑“或”操作符-o优先级比-a

  • 括号:改变求值顺序,括号两边必须有空格,且要将括号本身引用起来,因为test要求条件语句的每一个元素都是独立的参数,且括号对Shell有特殊含义(新开一个子Shell)

[ \( "$count" -ge 0 \) -a \( "$count" -lt 10 \) ]

25. exit

-exit n:返回退出码n

26. 空命令:

什么都不干,可以用在谋改革判断分支中,因为每个匹配的语句分支都需要对应的命令

27. sleep

sleep n:挂起程序执行n秒

28. nohup

希望某个程序在登出后继续运行,使用nohup命名运行该程序

29. break

退出循环,break n退出第n层内循环

for file
do 
    ...
    while [ "$count" -lt 10 ]
    do
        ...
        if [ -n "$error" ]
        then
            # 当error不为空,退出while和for循环
            break 2
        fi
    done
    ..
done

30. continue

跳过当前迭代中剩下的命令,continue n跳过最内侧的n个循环中的命令,继续往下执行

31. getopts

内建命令,专门用来在循环中执行处理命令行参数

getopts options variable

  • options中单个字符表示选项,如果选项后还需要参数,字符后要加冒号。mt:表示程序支持-m``-t选项,其中-t还需要一个参数

  • 如果减号后的字符没有在options中列出,会在返回为0的退出状态之前将问号保存在variable中,向标准错误写入错误信息,告诉用户指定的选项有问题

  • 如果getopts没有在选项后找到要求的参数,会将问号保存到变量中并向标准错误输出错误信息。否则,就将选项字符保存在变量中,把用户指定的参数放在一个叫做OPTARG的特殊变量中

  • 特殊变量OPTIND初始值为1,随后每当getopts返回时都会被更新为下一个要处理的命令行参数的序号

while getopts mt: option
do
    case "$option" in
        m) mailopt=TRUE;;
        t) interval=$OPTARG;;
        \?) exit 1;;
    esac
done

32. read

  • read variables从标准输入中读取一行,将第一个单词分配给variables中第一个变量,将第二个单词分配给第二个变量,以此类推。

  • 碰到文件结尾,或用户键入ctrl+dread会返回为0的退出状态码

cat $* |
while read line
do
    echo "$line"
done
  • 如果行中包含反斜线或前导空白字符,反斜线会由Shell解释,前导空白字符会从读入的行中删除。read -r避免解释反斜线。(可以修改变量IFS保留前导空格)

33. basename

剥离参数的所有目录部分,得到其基础文件名

34. printf

  • 格式化输出信息,格式化字符串中的每个百分号(格式规范)都有一个相应的参数,除了特殊规范%%,他会显示一个百分号。

  • 不会在尾部加一个换行符,能够理解转义序列

printf的格式规范字符

字符功能
%d整数
%u无符号整数
%o八进制整数
%x十六进制整数,使用a-f
%X十六进制整数,使用A-F
%c单个字符
%s字符串字面量
%b包含转义字符的字符串
%%百分号

%s不处理转义字符,%b强制解释转义字符

  • 转换规范:%[flags] [width] [.precision] type
$ printf "%+d\n%+d\n" 10 -10
+10
-10

$ printf "%-15.15s\n" "this is more than 15 chars long."
this is more th

$ printf "%*s%*.*s\n" 12 "test one" 10 2 "test two"
    test one        te

printf的格式规范修饰符

修饰符含义
Flags
-左对齐值
+在整数前加上+或-
(space)在正数前加上空格,负数前面加上-,对齐
#在八进制数前加上0,在十六进制数前加上0x或0X
width字段最小宽度;*表示使用下一个参数作为宽度
precision显示整数时使用的最小位数,值左侧用0填充;显示字符串时使用的最大字符数;*表示使用下一个参数作为精度

35. export

导出变量,只要子Shell已启动,导出的变量都会被复制到子Shell,而局部变量不会

  • export -p得到列表,包含了导出的变量和值,这些是在用户登录后由登录Shell所导出的
$ export -p
declare -x CLASSPATH=".:/usr/local/jdk1.8.0_131//jre/lib/rt.jar:/usr/local/jdk1.8.0_131//lib/dt.jar:/usr/local/jdk1.8.0_131//lib/tools.jar"
declare -x HISTCONTROL="ignoredups"
declare -x HISTSIZE="1000"
declare -x HOME="/root"
declare -x HOSTNAME="CENTOS-MINION-2"
declare -x JAVA_HOME="/usr/local/jdk1.8.0_131/"
...

36. .(dot)命令

. file:在当前Shell中执行file的内容

37. exec

  • exec program:使用新程序替换现有的程序,不会有进程处于挂起状态,由于UNIX系统执行进程的方式,exec所替换的程序启动时间也更快

  • 还可以用来关闭标准输入,然后使用其他你想要读取的文件重新打开它

exec < infile
exec > report

#将标准输入重新分配回终端
exec < /dev/tty

38. set

  • Shell的内建命令,设置各种Shell选项、重新为位置参数$1、$2…赋值
$ set one two three
$ echo $1:$2:$3
one:two:three
  • set -x打开跟踪模式;set +x关闭跟踪模式;

  • 无参数的set会输出一个按照字母顺序排序的变量列表,是存在于当前环境中的局部变量或导出变量

  • --:告诉set对于后续出现的连接符或参数形式的单词,均不视为其选项;是考虑到可能会出现以-起始的行、全部是空白字符或者空行

  • set -o mode:启动行编辑模式,mode可以是vi或emacs

39. readonly

  • 指定在程序随后的执行过程中,值都不会发生改变的那些变量,如:readonly PATH HOME,如果之后再视图给这两个变量赋值,会输出错误信息

  • 变量的只读属性不会传给子Shell

  • 只要将变量设为只读,就没有“后悔药”

40. unset

从环境中删除谋某个变量;不能对只读变量、IFS/MAILCHECK/PATH/PS1/PS2使用unset,

$ x=100
$ echo $x
100
$ unset x 
$ echo $x
$
  • -f:删除函数

41. eval

  • eval args:使得Shell对args求值,然后执行求值结果;常用于从变量中构造命令行,实际上可以实现对命令行的二次扫描;
  • 如果变量中包含了任何必须由Shell解释的字符,就必须用到eval
$ cat last
eval echo \$$#
$ last one two three four
four
#得到最后一个文件
$ last *
zoo_report
  • 还可以用来创建指向变量的“指针”
$ x=100
$ ptrx=x
$ eval echo \$$ptrx
100
$ eval $ptrx=50
$ echo $x
50

42. wait

  • wait job:暂停执行,直到job所标识的进程运行结束,job可以是进程ID或作业ID。如果没有提供job,Shell会等待所有子进程结束

43. trap

  • trap commands signals:告诉Shell只要接收到signals中列出的信号,就执行commands(如果不止一个命令,要全部放入引号中),信号以名称或编号形式指定
#exit是必须的,否则程序会一直停留在接收到信号时的执行位置上
trap "rm $WORKDIR/work$$ $WORKDIR/dataout$$; exit" INT

信号编号与名称

信号#信号名称产生原因
0EXIT退出Shell
1HUP挂起
2INT中断(如按下DELETE键或ctrl+c)
3QUIT退出
6ABRP中止
9KILL销毁进程
14ALRM超时
15TERM软件终止信号(默认由kill发送)
  • 不使用参数,trap会打印出当前的信号处理方式

  • 如果第一个参数是空串:trap "" signals,当Shell接收到signals指定的信号时,会将其忽略

  • 如果忽略了某个信号,子Shell也会忽略;如果指定了某个信号的处理程序,子Shell自动采用默认处理方式,而不是指定的处理程序

  • 使用trap signals,会将signals中列出的信号处理方式恢复成默认行为

  • Shell在执行trap时扫描命令行,在接收到信号列表中的信号时还会再扫描一遍:

trap "echo $count lines processed >> $LOGFILE; exit" HUP INT TERM

#为了防止count被提前替换,将命令放入单引号中
trap 'echo $count lines processed >> $LOGFILE; exit' HUP INT TERM

44. return

return n:n为函数的返回状态,可以用变量$?访问它

45. type

接受一个或多个命令作为参数,告诉你这些命令是什么类型

$ type echo
echo is a shell builtin

$ type ls
ls is aliased to `ls --color=auto'

$ type cat
cat is /usr/bin/cat

$ type nu
nu is a function

46. history

访问命令历史记录

$ history
....

$  history 5
  885  type echo
  886  type ls
  887  type cat
  888  history
  889  history 5

47. fc

  • 为历史记录中的若干命令启动一个编辑器或将历史命令列表写入终端。后一种,使用-l指定命令列表

  • -n忽略命令编号

  • fc -s old=new first执行选中的命令,无需事先编辑

fc -l 50-53
#最近20条命令写入到标准输出
fc -n -l -20
#将最近的sed命令送入vi中编辑
fc -e vi sed
#将编号104的命令中的abc替换成def,然后重新执行
fc -s abc=def 104

48. r (Korn Shell才有)

重新显示上一条命令并立即执行

#运行上一条cat命令
$ r cat
cat doc/planA
#将cat命令中第一次出现的planA替换成planB
$ r cat planA=planB

49. typeset (Korn Shell才有)

  • -i:声明整数类型
  • 整数表达式可以分配给整数类型的变量,甚至不需要((…))
$ typeset -i i
$ i=hello
ksh: i: bad number

50. alias

alias name=string:自定义命令

  • 如果别名以空格结束,则会对其之后的单词执行别名替换
  • 把命令引用起来或放在反斜线之后可以避免进行别名替换
alias ll='ls -l'

51. unalias

unalias name:删除别名
unalias -a:删除所有别名

52. jobs

打印出尚未完成的作业状态

53. kill

终止后台作业

54. fg

ctrl+z挂起当前运行的作业,fg在前台恢复执行当前作业

55. bg

在后台恢复执行当前作业


语句结构

1. if

if command-t1
then
    command
    command
fi

# else
if command-t1
then
    command
    ...
else
    command
    ...
fi

# elif-else
if command-t1
then
    command
    ...
elif command-t2
then
    command
    ...
else
    command
    ...
fi
  • command-tx命令的退出状态会被测试,如果为0,则执行then和fi之间的命令

2. case

case value in
pattern1) command
          ...
          command;;
pattern2) command
          ...
          command;;
...
patternn) command
          ...
          command;;
esac
  • ;;类似于break

  • 模式匹配:与文件名替换相同,?任意单个字符、*零个或多个任意字符、[...]中括号中出现的任意单个字符,符号|用于两个模式之间,效果等同于逻辑“或”

3. for

for var in word1 word2 ... wordn
do
    command
    ...
done
  • 不使用列表,Shell会自动遍历命令行中输入的所有参数,和for var in "$@"一样:
for var
do
    command
    ...
done
  • 因为Shell将循环视为一种独立的小程序,任何出现在代码块关闭语句之(done/fi/esac)后的内容都可以使用重定向,也可以利用&将循环放入后台,甚至是作为命令管道的一部分
# 放入后台
for file in memo[1-4]
do
    run $file
done &

# 重定向
for i in 1 2 3 4
do
    echo $i
done > loopout

# 数据导出
for i in 1 2 3 4
do
    echo $i
done | wc -l
  • 单行循环

列表最后一项后面加分号,循环中每个命令后面加分号,do后面不加

for i in 1 2 3 4; do echo $i; done

4. while

while command-t
do
    command
    ...
done

5. until

until command-t
do
    command
    ...
done

只要command-t返回码不为0,就会不停执行代码块

6. 算术表达式

内建整数算术操作,算术扩展:$((express)),(express两边和括号之间不必有空格),出现在算术扩展中的有效元素只有操作符、数字和变量,未定义的变量或空串值被视为0

$ i=1
$ j=$((i+1))
$ echo $j
2

express中可以包含常量、Shell变量(不需要美元符号)及操作符,按照优先级从高到低的次序,操作符如下:

符号含义
-减号
~按位取反
!逻辑反
* / %乘、除、求余
+ -加、减
<< >>左移、右移
<= >= < >比较
== !=等于、不等于
&按位与
^按位异或
|按位或
&&逻辑与
||逻辑或
expr1 ? expr2 : expr3条件运算符
= *= /= %=赋值
+= <<= >>=赋值
&= ^= |=赋值
  • 整数算数
    Bash和Korn Shell都可以不使用算数扩展求值算术表达式,因为不会执行扩展,其本身可以作为命令使用;这样就可以将算数表达式用于if、while和until命令中:
$ x=10
$ ((x = x * 12))
$ echo $x
120

if ((i == 100))
then
    ...
fi

不同基数的数字:base#number,尽管被设置为按照八进制显示,但分配给该变量的值默认基数仍然是十进制,除非另行指定

$ typeset -i i=8#100
$ echo $i
8#100
$ i=50
$ echo $i
8#62

7. 函数

name () { command; ... command; }
  • 如果函数体和花括号出现在同一行,{和第一条命令之间必须至少有一个空白字符,最后一条命令和}之间必须有一个分号

  • 函数仅存在于所定义它的Shell中,无法传给子Shell,因为函数是在当前Shell中执行的

  • 在函数内部使用exit,不仅会终止函数的执行,还会使调用该函数的Shell程序退出;如果只想退出函数,可以使用return n命令,n为函数的返回状态

  • 可以将函数写进ENV文件中,启动新Shell就能直接使用

  • bash和Korn Shell可以只用局部变量:typeset j

  • Korn Shell在变量FPATH中搜索匹配函数名的文件

8. 数组

  • 数组元素以0为起始
  • [*]作为下标,在命令行中生成数组的的所有元素
  • ${#array[*]}获得array中的元素个数
  • 包含非连续值的数组成为稀疏数组
  • 双引号中使用数组元素可以省略美元符号和花括号,而且,如果声明的是整数数组,就算不在双引号中也可以省略。另外,下标表达式中的变量前面不需要使用美元符号
$ typeset -i array
$ array[0]=100
$ array[1]=50
$ (( array[2] = array[0] + array[1] ))
$ echo ${array[2]}
150
$ i=1
$ echo ${array[i]}
50
$ array[3]=array[0]+array[2]
$ echo ${array[3]}
250

引用

Shell能够识别4中不同的引用字符,单引号、双引号、反斜线和反引号

1. 单引号
  • 出现在单引号中的特殊字符,Shell会将其全部忽略

  • 传参时,引号会被Shell删除,并不会传入程序中;

$ t='* 233'

# 执行变量替换后,引号没有了,会执行变量名替换,sad!!!
$ echo $t
dingtest dingtest26787 petalk 233
2. 双引号
  • Shell会解析双引号中的美元符号、反引号、反斜线,所以,Shell会在双引号中完成变量名替换,但不会进行文件名替换
$ t='* 233'

# 执行变量替换后,引号没有了,会执行变量名替换,sad!!!
$ echo $t
dingtest dingtest26787 petalk 233

# 加了双引号就好了
$ echo "$t"
* 233
3. 反斜线
  • 作为前缀使用,在功能上相当于单个字符周围放置单引号

  • 作为输入行的最后一个字符,Shell将其视为续行符

  • 双引号中使用反斜线去除特殊字符(反斜线、美元符号、反引号、换行符、双引号)的含义(删除反斜线),如果后面没有特殊字符,Shell忽略该反斜线(不删除反斜线),继续往后处理

4. 命令替换
4.1. 反引号
  • 告诉Shell将其中的命令使用命令输出代替
$ echo The date is `date`
The date is Sun Dec 30 21:49:19 CST 2018
4.2. $(…)结构
  • 比反引号更易于嵌套
  • 双引号中会解释命令替换
$ echo $(who | wc -l)
1

变量、参数与环境

变量

1. 基础
  • 变量名以字母或下划线开头,后面跟上零个或多个字母数字或下划线

  • count=1等号两边不能有空格

  • Shell没有数据结构的概念,都是字符串

  • 对变量赋值时,Shell不执行文件名替换

  • 没有值的变量叫做未定义变量,值为空(null);Shell执行变量替换时,为空的值会被从命令行删除

  • ${variable}结构,在变量名最后一个字符后面跟着的是字母及数字字符或下划线时使用,使得变量可以正常替换

参数

即便是执行自己的Shell程序,Shell也会进行正常的命令行处理,这意味着在指定程序参数时可以利用这些处理步骤,进行文件名替换和变量替换。

但是,参数传递过程中会丢失引号,可以在自己的Shell程序中视情况给变量引用加上双引号

1. 位置参数
  • Shell会自动将第一个参数保存在特殊的Shell变量1中,这是在Shell完成正常的命令行处理后(I/O重定向、变量替换、文件名替换等)被赋值的。
  • $1表示使用程序的第一个参数进行替换
  • ${n}
    • 当给程序传递的参数多于9个时,要访问参数10需要写成${10}
2. 特殊的参数变量
参数含义
$#传递给程序的参数数量或者由set语句设置的参数数量
$*引用所有的位置参数$1、$2…
$@“$@“以”$1”…的形式引用所有的位置参数
$0所执行的程序名
$$所执行程序的进程ID
$!送入后台执行的最近一个程序的进程ID
$?最近执行的非后台命令的退出状态码
$-生效的当前选项标志(参见set语句)
  • 变量$#

    • 包含了命令行中输入的参数个数
  • 变量$*

    • 引用传给程序的所有参数
  • 变量$@

    • for arg in $*中传进来的参数会丢失引号,可以使用"$@"代替,那么传入程序的会是"$1"、"$2"...,关键在于$@两边的引号,如果没有了引号,该变量效果$*无异
    for arg in "$@"
    do
        echo $arg
    done
    
3. 参数替换
参数含义
p a r a 或 para 或 para{para}替换成para的值
${para:-value}若para已设置且不为空,使用它的值;否则,使用value
${para-value}若para已设置(可为空),替换为它的值,否则,替换为value
${para:=value}若para已设置且不为空,使用它的值;否则,替换为value并将其赋给para
${para=value}若para已设置(可为空),使用它的值,否则,替换为value,并将其赋给para
${para:?value}若para已设置且不为空,使用它的值,否则,将value写入标准错误,然后退出。
${para?value}若para已设置(可为空),替换为它的值;否则,将value写入标准错误并推出。
${para:+value}若para已设置且不为空,替换成value;否则,替换为空。与${para:-value}效果相反
${para+value}若para已设置(可为空),替换成value;否则,替换为空。
${#para}替换为para的长度
${para#pattern}从para左边开始删除pattern的最短匹配,余下内容作为参数替换的结果,不会修改变量的值
${para##pattern}从para左边开始删除pattern的最长匹配
${para%pattern}从para右边开始删除pattern的最短匹配
${para%%pattern}从para右边开始删除pattern的最长匹配
  • ${para:=value}:不能单独作为命令,因为执行完替换操作后,Shell会尝试执行替换结果;要作为一个单独的命令,需要使用空命令:
: ${PHONEBOOK:=$HOME/phonebook}
  • p a r a : ? v a l u e 和 {para:?value}和 para:?value{para?value}:如果忽略value,则向标准错误写入parameter: parameter null or not set

  • 模式匹配:pattern中可以使用Shell文件名替换字符(*、?、[…]、!和@)

$ var=testcase
$ echo ${var%e}
testcas
#变量的值不变
$ echo $var
testcase
$ echo ${var%s*e}
testca
$ echo ${var%%s*e}
te
$ echo ${var#?e}
stcase
$ echo ${var#*s}
tcase
$ echo ${var##*s}
e
#没有匹配会输出整个变量名
$ echo ${var#teas}
testcase

环境

1. 子Shell与导出变量
  • 除了Shell内建命令之外的其他命令通常都是在一个全新的Shell实例中执行的,我们称其为子Shell

  • 子Shell执行完毕时,它所创建的变量无法再被访问

  • 局部变量与导出变量

    • 未被导出的变量都是局部变量
    • 导出的变量及其值会被复制到子Shell的环境中,在其中可以访问并修改这些导出变量。但是这些修改不会影响到父Shell中的变量
    • 导出变量不仅保持在直接生成的子Shell中,对于由这些子Shell所生成的子Shell也不例外
    • 变量可以在赋值前后随时导出,但是只取其导出时的值,不再理会之后做出的改变
  • 可以通过将赋值语句放在命令名之前,将Shell变量添加到该命令的环境中

PHONEBOOK=$HOME/misc/phone rolo
#等同于
(PHONEBOOK=$HOME/misc/phone; export PHONEBOOK; rolo)
2. 环境变量
变量名含义
PS1命令行提示符的字符序列
PS2辅命令行提示符
HOME主目录,用户登录后所处的位置
PATH搜索用户命令的目录列表,以冒号分隔
PWD当前目录
OLDPWD前一个当前目录的完整路径
CDPATHcd命令没有给出目录的完整路径时在该列表中搜索
TERM终端类型,ansi/vt100/xterm等等
TZ决定当前时区
IFS内部字段分隔符
ENV当以交互方式启动的时候,Shell会在当前环境下所执行的文件名
HISTSIZE可保存的闲钱输入过的命令数量
HISTFILE保存命令历史的文件
FPATHKorn Shell在变量FPATH中搜索匹配函数名的文件

一旦登出,对PS1等做出的改变会失效,除非将修改保存到.profile文件中

  • HOME:主目录,用户登录后所处的位置,不带参数的cd命令将该目录作为默认目的地

  • PATH:不将当前目录放在最先搜索的位置,避免特洛伊木马攻击

echo $PATH
/bin:/usr/bin:.
  • CDPATH:不会在登录时自动设置好(echo $CDPATH为空),需要明确将其设置为一系列目录

  • TZ:最简单的TZ的设置由时区名(长度至少3个字符)和一个数字(指定了小时数),现代Linux也可以指定地理区域来指定时区

  • IFS:当Shell解析read命令输入、命令替换输出以及执行变量替换式,会用到;在执行变量赋值时并不使用

3. (…)和{…;}

命令分组

  • (...):小括号中放入一条或多条命令,这些命令会在子Shell中执行

  • {...;}:命令在当前Shell执行,如果花括号中的命令全写在同一行,左花括号后一定要有一个空格,分号必须出现在最后一个命令的末尾

{ echo ".ls 2"; cat memo; } | nroff -Tlp | lp 
  • I/O重定向和管道可以作用在一组命令上:
#三个程序被放入后台,标准错误重定向到errors文件
(prog1; prog2; prog3) 2>errors &

编辑器

1. ed

旧式行编辑器,交互式

# 将所有的p.o(.匹配任意单个字符)修改成XXX
# 1,$(范围限定符,表示从文章的第一行到最后一行)指明在全文范围内应用替换操作,替换操作格式为s/old/new/g
# s表明是替换操作,斜线用来界定替换内容和被替换内容,g表明执行全局替换,而不仅仅是替换某一行
1,$s/p.o/XXX/g

#打印全文,查看修改结果
1,$p

2. sed

流编辑器,非交互式,不会修改原始输入文件,结果写入标准输出

-n默认不打印任何行,与p命令搭配使用,打印出符合指定范围或模式的所有行

d命令删除文本行

# 将intro文件中的Unix替换成UNIX
# 单引号避免Shell解释其中的反斜线
sed 's/Unix/UNIX/' intro

# 只打印前两行
sed -n '1,2p' intro

# 删除行1和2
sed '1,2d' intro

# 将包含jan的所有行中的第一个-1改成-5
sed '/jan/s/-1/-5/'

# 在制表符的位置显示\t不可打印字符显示为\nn(nn为字符的八进制值)
sed -n l <file>

3. vi

行编辑器,set -o vi开启

基本的vi行编辑命令

命令含义
h向左移动一个字符
l向右移动一个字符
b向左移动一个单词
w向右移动一个单词
0移动到行首
$移动到行尾
x删除光标所在的字符
dw删除贯标所在的单词
rc将光标所在的字符修改成c
a进入输入模式并在当前字符之后输入文本
i进入输入模式并在当前字符之前输入文本
k获得历史记录中上一条命令
j获得历史记录中下一条命令
/string搜索历史记录中包含string的最近一条命令,如果string没指定,使用先前的搜索内容

4. emacs

行编辑器,set -o emacs开启

基本的emacs行编辑命令

命令含义
ctrl+b向左移动一个字符
ctrl+f向右移动一个字符
esc f向前移动一个单词
esc b向后移动一个单词
ctrl+a移动到行首
ctrl+e移动到行尾
ctrl+d删除当前字符
esc d删除当前单词
erase char(用户自定义#或ctrl+h),删除上一个字符
ctrl+p从历史记录中获得上一条命令
ctrl+n从历史记录中获得下一条命令
ctrl+r string搜索历史记录,查找包含string的最近一条命令
本书共分五部分,详细介绍了shell编程技巧,各种UNIX命令及语法,还涉及了UNIX下的文字处理以及少量的系统管理问题。本书内容全面、文字简洁流畅,适合Shell编程人员学习、参考。 目 录 译者序 前言 第一部分 shell 第1章 文件安全与权限 1 1.1 文件 1 1.2 文件类型 2 1.3 权限 2 1.4 改变权限位 4 1.4.1 符号模式 4 1.4.2 chmod命令举例 5 1.4.3 绝对模式 5 1.4.4 chmod命令的其他例子 6 1.4.5 可以选择使用符号模式或绝对模式 7 1.5 目录 7 1.6 suid/guid 7 1.6.1 为什么要使用suid/guid 8 1.6.2 设置suid/guid的例子 8 1.7 chown和chgrp 9 1.7.1 chown举例 9 1.7.2 chgrp举例 9 1.7.3 找出你所属于的用户组 9 1.7.4 找出其他用户所属于的组 10 1.8 umask 10 1.8.1 如何计算umask值 10 1.8.2 常用的umask值 11 1.9 符号链接 12 1.9.1 使用软链接来保存文件的多个映像 12 1.9.2 符号链接举例 12 1.10 小结 13 第2章 使用find和xargs 14 2.1 find命令选项 14 2.1.1 使用name选项 15 2.1.2 使用perm选项 16 2.1.3 忽略某个目录 16 2.1.4 使用user和nouser选项 16 2.1.5 使用group和nogroup选项 16 2.1.6 按照更改时间查找文件 17 2.1.7 查找比某个文件新或旧的文件 17 2.1.8 使用type选项 17 2.1.9 使用size选项 18 2.1.10 使用depth选项 18 2.1.11 使用mount选项 18 2.1.12 使用cpio选项 18 2.1.13 使用exec或ok来执行shell命令 19 2.1.14 find命令的例子 20 2.2 xargs 20 2.3 小结 21 第3章 后台执行命令 22 3.1 cron和crontab 22 3.1.1 crontab的域 22 3.1.2 crontab条目举例 23 3.1.3 crontab命令选项 23 3.1.4 创建一个新的crontab文件 24 3.1.5 列出crontab文件 24 3.1.6 编辑crontab文件 24 3.1.7 删除crontab文件 25 3.1.8 恢复丢失的crontab文件 25 3.2 at命令 25 3.2.1 使用at命令提交命令或脚本 26 3.2.2 列出所提交的作业 27 3.2.3 清除一个作业 27 3.3 &命令 27 3.3.1 向后台提交命令 28 3.3.2 用ps命令查看进程 28 3.3.3 杀死后台进程 28 3.4 nohup命令 29 3.4.1 使用nohup命令提交作业 29 3.4.2 一次提交几个作业 29 3.5 小结 30 第4章 文件名置换 31 4.1 使用* 31 4.2 使用? 32 4.3 使用[...]和[!...] 32 4.4 小结 33 第5章 shell输入与输出 34 5.1 echo 34 5.2 read 35 5.3 cat 37 5.4 管道 38 5.5 tee 39 5.6 标准输入、输出和错误 40 5.6.1 标准输入 40 5.6.2 标准输出 40 5.6.3 标准错误 40 5.7 文件重定向 40 5.7.1 重定向标准输出 41 5.7.2 重定向标准输入 42 5.7.3 重定向标准错误 42 5.8 结合使用标准输出和标准错误 43 5.9 合并标准输出和标准错误 43 5.10 exec 44 5.11 使用文件描述符 44 5.12 小结 45 第6章 命令执行顺序 46 6.1 使用&& 46 6.2 使用|| 46 6.3 用()和{ }将命令结合在一起 47 6.4 小结 48 第二部分 文本过滤 第7章 正则表达式介绍 49 7.1 使用句点匹配单字符 50 7.2 在行首以^匹配字符串或字符序列 50 7.3 在行尾以$匹配字符串或字符 51 7.4 使用*匹配字符串中的单字符或其重复 序列 51 7.5 使用\屏蔽一个特殊字符的含义 52 7.6 使用[]匹配一个范围或集合 52 7.7 使用\{\}匹配模式结果出现的次数 53 7.8 小结 55 第8章 grep家族 56 8.1 grep 57 8.1.1 双引号引用 57 8.1.2 grep选项 57 8.1.3 查询多个文件 57 8.1.4 行匹配 57 8.1.5 行数 58 8.1.6 显示非匹配行 58 8.1.7 精确匹配 58 8.1.8 大小写敏感 58 8.2 grep和正则表达式 58 8.2.1 模式范围 59 8.2.2 不匹配行首 59 8.2.3 设置大小写 59 8.2.4 匹配任意字符 59 8.2.5 日期查询 59 8.2.6 范围组合 60 8.2.7 模式出现机率 60 8.2.8 使用grep匹配“与”或者“或”模式 61 8.2.9 空行 61 8.2.10 匹配特殊字符 61 8.2.11 查询格式化文件名 61 8.2.12 查询IP地址 61 8.3 类名 62 8.4 系统grep命令 62 8.4.1 目录 63 8.4.2 passwd文件 63 8.4.3 使用ps命令 63 8.4.4 对一个字符串使用grep 64 8.5 egrep 64 8.6 小结 65 第9章 AWK介绍 66 9.1 调用awk 66 9.2 awk脚本 67 9.2.1 模式和动作 67 9.2.2 域和记录 67 9.2.3 awk中正则表达式及其操作 70 9.2.4 元字符 70 9.2.5 条件操作符 70 9.2.6 awk内置变量 73 9.2.7 NF、NR和FILENAME 74 9.2.8 awk操作符 75 9.2.9 内置的字符串函数 78 9.2.10 字符串屏蔽序列 80 9.2.11 awk输出函数printf 81 9.2.12 printf修饰符 81 9.2.13 awk数组 86 9.3 小结 88 第10章 sed 用法介绍 89 10.1 sed怎样读取数据 89 10.2 调用sed 89 10.2.1 保存sed输出 90 10.2.2 使用sed在文件中查询文本的方式 90 10.2.3 基本sed编辑命令 90 10.3 sed和正则表达式 91 10.4 基本sed编程举例 91 10.4.1 使用p(rint)显示行 91 10.4.2 打印范围 91 10.4.3 打印模式 92 10.4.4 使用模式和行号进行查询 92 10.4.5 匹配元字符 92 10.4.6 显示整个文件 92 10.4.7 任意字符 92 10.4.8 首行 92 10.4.9 最后一行 93 10.4.10 打印行号 93 10.4.11 附加文本 93 10.4.12 创建sed脚本文件 94 10.4.13 插入文本 94 10.4.14 修改文本 95 10.4.15 删除文本 96 10.4.16 替换文本 96 10.5 使用替换修改字符串 97 10.6 将sed结果写入文件命令 97 10.7 从文件中读文本 98 10.8 匹配后退出 98 10.9 显示文件中的控制字符 99 10.10 使用系统sed 99 10.10.1 处理控制字符 99 10.10.2 处理报文输出 101 10.10.3 去除行首数字 101 10.10.4 附加文本 102 10.10.5 从shell向sed传值 102 10.10.6 从sed输出中设置shell变量 102 10.11 快速一行命令 102 10.12 小结 103 第11章 合并与分割 104 11.1 sort用法 104 11.1.1 概述 104 11.1.2 sort选项 104 11.1.3 保存输出 105 11.1.4 sort启动方式 105 11.1.5 sort对域的参照方式 105 11.1.6 文件是否已分类 105 11.1.7 基本sort 106 11.1.8 sort分类求逆 106 11.1.9 按指定域分类 106 11.1.10 数值域分类 106 11.1.11 唯一性分类 107 11.1.12 使用k的其他sort方法 108 11.1.13 使用k做分类键排序 108 11.1.14 指定sort序列 108 11.1.15 pos用法 108 11.1.16 使用head和tail将输出分类 109 11.1.17 awk使用sort输出结果 109 11.1.18 将两个分类文件合并 110 11.2 系统sort 110 11.3 uniq用法 111 11.4 join用法 112 11.5 cut用法 114 11.5.1 使用域分隔符 115 11.5.2 剪切指定域 115 11.6 paste用法 116 11.6.1 指定列 116 11.6.2 使用不同的域分隔符 116 11.6.3 paste命令管道输入 117 11.7 split用法 117 11.8 小结 118 第12章 tr用法 119 12.1 关于tr 119 12.1.1 字符范围 119 12.1.2 保存输出 120 12.1.3 去除重复出现的字符 120 12.1.4 删除空行 120 12.1.5 大写到小写 121 12.1.6 小写到大写 121 12.1.7 删除指定字符 121 12.1.8 转换控制字符 122 12.1.9 快速转换 122 12.1.10 匹配多于一个字符 123 12.2 小结 123 第三部分 登录环境 第13章 登录环境 125 13.1 /etc/profile 125 13.2 用户的$HOME.profile 128 13.3 stty用法 129 13.4 创建.logout文件 131 13.5 小结 131 第14章 环境和shell变量 132 14.1 什么是shell变量 132 14.2 本地变量 132 14.2.1 显示变量 133 14.2.2 清除变量 133 14.2.3 显示所有本地shell变量 133 14.2.4 结合变量值 134 14.2.5 测试变量是否已经设置 134 14.2.6 使用变量来保存系统命令参数 135 14.2.7 设置只读变量 135 14.3 环境变量 136 14.3.1 设置环境变量 136 14.3.2 显示环境变量 136 14.3.3 清除环境变量 137 14.3.4 嵌入shell变量 137 14.3.5 其他环境变量 139 14.3.6 set命令 140 14.3.7 将变量导出到子进程 140 14.4 位置变量参数 141 14.4.1 在脚本中使用位置参数 142 14.4.2 向系统命令传递参数 142 14.4.3 特定变量参数 143 14.4.4 最后的退出状态 144 14.5 小结 145 第15章 引号 146 15.1 引用必要性 146 15.2 双引号 146 15.3 单引号 147 15.4 反引号 147 15.5 反斜线 148 15.6 小结 149 第四部分 基础shell编程 第16章 shell脚本介绍 151 16.1 使用shell脚本的原因 151 16.2 脚本内容 151 16.3 运行一段脚本 152 16.4 小结 153 第17章 条件测试 154 17.1 测试文件状态 154 17.2 测试时使用逻辑操作符 155 17.3 字符串测试 155 17.4 测试数值 156 17.5 expr用法 157 17.5.1 增量计数 158 17.5.2 数值测试 158 17.5.3 模式匹配 158 17.6 小结 159 第18章 控制流结构 160 18.1 退出状态 160 18.2 控制结构 160 18.2.1 流控制 161 18.2.2 循环 161 18.3 if then else语句 161 18.3.1 简单的if语句 162 18.3.2 变量值测试 162 18.3.3 grep输出检查 163 18.3.4 用变量测试grep输出 163 18.3.5 文件拷贝输出检查 164 18.3.6 当前目录测试 164 18.3.7 文件权限测试 165 18.3.8 测试传递到脚本中的参数 165 18.3.9 决定脚本是否为交互模式 165 18.3.10 简单的if else语句 166 18.3.11 变量设置测试 166 18.3.12 检测运行脚本的用户 166 18.3.13 将脚本参数传入系统命令 167 18.3.14 null:命令用法 167 18.3.15 测试目录创建结果 168 18.3.16 另一个拷贝实例 169 18.3.17 多个if语句 169 18.3.18 测试和设置环境变量 169 18.3.19 检测最后命令状态 170 18.3.20 增加和检测整数值 171 18.3.21 简单的安全登录脚本 172 18.3.22 elif用法 173 18.3.23 使用elif进行多条件检测 173 18.3.24 多文件位置检测 174 18.4 case语句 175 18.4.1 简单的case语句 175 18.4.2 对匹配模式使用| 176 18.4.3 提示键入y或n 177 18.4.4 case与命令参数传递 177 18.4.5 捕获输入并执行空命令 178 18.4.6 缺省变量值 179 18.5 for循环 180 18.5.1 简单的for循环 181 18.5.2 打印字符串列表 181 18.5.3 对for循环使用ls命令 181 18.5.4 对for循环使用参数 182 18.5.5 使用for循环连接服务器 183 18.5.6 使用for循环备份文件 183 18.5.7 多文件转换 183 18.5.8 多sed删除操作 184 18.5.9 循环计数 184 18.5.10 for循环和本地文档 184 18.5.11 for循环嵌入 185 18.6 until循环 186 18.6.1 简单的until循环 186 18.6.2 监视文件 187 18.6.3 监视磁盘空间 187 18.7 while循环 188 18.7.1 简单的while循环 188 18.7.2 使用while循环读键盘输入 188 18.7.3 用while循环从文件中读取数据 189 18.7.4 使用IFS读文件 189 18.7.5 带有测试条件的文件处理 190 18.7.6 扫描文件行来进行数目统计 191 18.7.7 每次读一对记录 193 18.7.8 忽略#字符 193 18.7.9 处理格式化报表 194 18.7.10 while循环和文件描述符 196 18.8 使用break和continue控制循环 197 18.8.1 break 197 18.8.2 跳出case语句 197 18.8.3 continue 197 18.8.4 浏览文件行 198 18.9 菜单 199 18.10 小结 201 第19章 shell函数 202 19.1 在脚本中定义函数 203 19.2 在脚本中使用函数 203 19.3 向函数传递参数 203 19.4 从调用函数中返回 203 19.5 函数返回值测试 204 19.6 在shell中使用函数 204 19.7 创建函数文件 204 19.8 定位文件 205 19.9 检查载入函数 205 19.10 执行shell函数 205 19.10.1 删除shell函数 206 19.10.2 编辑shell函数 206 19.10.3 函数举例 207 19.10.4 将函数集中在一起 219 19.11 函数调用 219 19.11.1 在脚本中调用函数 219 19.11.2 从函数文件中调用函数 220 19.12 定位文件不只用于函数 222 19.13 小结 223 第20章 向脚本传递参数 224 20.1 shift命令 225 20.1.1 shift命令简单用法 225 20.1.2 命令行输入的最后一个参数 225 20.1.3 使用shift处理文件转换 226 20.2 getopts 229 20.2.1 getopts脚本实例 229 20.2.2 getopts使用方式 231 20.2.3 使用getopts指定变量取值 231 20.2.4 访问取值方式 232 20.2.5 使用getopts处理文件转换 233 20.3 小结 235 第21章 创建屏幕输出 236 21.1 tput用法 236 21.1.1 字符串输出 236 21.1.2 数字输出 237 21.1.3 布尔输出 237 21.2 tput用法 237 21.2.1 设置tput命令 237 21.2.2 使用布尔输出 237 21.2.3 在脚本中使用tput 237 21.2.4 产生转义序列 238 21.2.5 光标位置 239 21.2.6 在屏幕中心位置显示文本 240 21.2.7 查找终端属性 240 21.2.8 在脚本中使用功能键 241 21.2.9 使用颜色 242 21.2.10 产生颜色 243 21.2.11 创建精致菜单 246 21.3 小结 251 第22章 创建屏幕输入 252 22.1 增加记录 252 22.2 删除记录 262 22.3 修改记录 266 22.4 查看记录 270 22.5 小结 273 第23章 调试脚本 274 23.1 一般错误 274 23.1.1 循环错误 274 23.1.2 典型的漏写引号 274 23.1.3 测试错误 274 23.1.4 字符大小写 275 23.1.5 for循环 275 23.1.6 echo 275 23.2 set命令 275 23.3 小结 276 第24章 shell嵌入命令 277 24.1 shell嵌入命令完整列表 277 24.1.1 pwd 277 24.1.2 set 278 24.1.3 times 278 24.1.4 type 278 24.1.5 ulimit 279 24.1.6 wait 279 24.2 小结 279 第五部分 高级shell编程技巧 第25章 深入讨论<< 281 25.1 快速创建一个文件 281 25.2 快速创建打印文档 281 25.3 自动选择菜单 282 25.4 自动ftp传输 283 25.5 访问数据库 286 25.6 小结 288 第26章 shell 工具 289 26.1 创建保存信息的文件 289 26.1.1 使用date命令创建日志文件 289 26.1.2 创建唯一的临时文件 290 26.2 信号 291 26.2.1 杀死一个进程 292 26.2.2 检测信号 293 26.3 trap 294 26.3.1 捕获信号并采取相应的行动 294 26.3.2 捕获信号并采取行动的另 一个例子 295 26.3.3 锁住终端 297 26.3.4 忽略信号 298 26.4 eval 300 26.4.1 执行含有字符串的命令 300 26.4.2 给每个值一个变量名 301 26.5 logger命令 302 26.5.1 使用logger命令 303 26.5.2 在脚本中使用logger命令 303 26.6 小结 305 第27章 几个脚本例子 306 27.1 pingall 306 27.2 backup_gen 306 27.3 del.lines 312 27.4 access.deny 313 27.5 logroll 316 27.6 nfsdown 317 27.7 小结 317 第28章 运行级别脚本 318 28.1 怎么知道系统中是否含有运行 级别目录 318 28.2 确定当前的运行级别 319 28.3 快速熟悉inittab 319 28.4 运行级别 320 28.4.1 各种运行级别 321 28.4.2 运行级别脚本的格式 321 28.4.3 安装运行级别脚本 322 28.5 使用inittab来启动应用程序 323 28.6 启动和停止服务的其他方法 324 28.7 小结 324 第29章 cgi脚本 325 29.1 什么是Web页面? 325 29.2 cgi 325 29.3 连接Web服务器 326 29.4 cgi和HTM脚本 326 29.4.1 基本cgi脚本 326 29.4.2 显示shell命令输出 328 29.4.3 使用SSI 330 29.4.4 访问计数器 330 29.4.5 使用一个链接来显示当前Web 环境变量 332 29.4.6 其他常用的环境变量 334 29.5 get和post方法简介 335 29.5.1 get方法 335 29.5.2 post方法 340 29.5.3 填充列表项 347 29.5.4 自动刷新页面 348 29.6 小结 349 附录 常用shell命令 350
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值