Skip to content

Latest commit

 

History

History
340 lines (308 loc) · 22 KB

Shell与Shell-scripts.md

File metadata and controls

340 lines (308 loc) · 22 KB

本文是《鸟哥的Linux私房菜》的读书笔记,学习内容来自:《鸟哥的Linux私房菜》,版权归鸟哥

关于shell

  1. 常见shell
    1. Bourne SHell (sh)
    2. 在 Sun 里头默认的 C SHell
    3. 商业上常用的 K SHell
    4. TCSH
    5. ...
  2. 关于shell 查看当前进程中使用的shell ps | grep $$ | awk '{print $4}'
    当前有哪些可以使用的shell?可以查看/etc/shells
    登录时,系统会给我用哪个shell?看/etc/passwd
    如何知道命令是来自于外部命令(指的是其他非 bash 所提供的命令) 或是内建在 bash 当中的呢?type [-tpa] name

shell变量

  1. 什么是变量?
    变量就是以一组文字或符号等,来取代一些配置或者是一串保留的数据!

  2. 如何显示变量?
    使用echo,变量在被取用时,前面必须要加上$才行。举例说明:echo $PATH或者echo ${PATH}

  3. 如何设置或者修改变量内容?
    使用=连接即可。举例:myName=wangzz
    值得注意的是:

    • 等号(=)两边不能直接接空格,错误实例yourName = Kobe,这与大多数人编程习惯不同,需要注意。
    • 变量名称只能是英文字母与数字,且不能以数字开头。(经过尝试,下划线也可以),错误示例: 2B=xx
    • 变量内容若有空格符可使用双引号"或单引号'将变量内容结合起来,但要注意:
      • 双引号内的特殊字符如$等,可以保有原本的特性,如下所示:var="lang is $LANG"echo $var可得lang is en_US
      • 单引号内的特殊字符则仅为一般字符 (纯文本),如下所示:var='lang is $LANG'echo $var可得lang is $LANG
    • 可用字符\将特殊符号(如 [Enter], $, , 空格符, '等)变成一般字符;
    • 在一串命令中,还需要使用由其他命令,可使用反单引号`命令`$(命令),比如:path=`pwd`
    • 如果想追加变量内容,比如想给name=Messi变量增加内容,可以这么做:name="$name"IsMagic,或者是name=${name}IsMagic
    • 若该变量需要在其他子程序运行,则需要以 export 来使变量变成环境变量:export PATH。经尝试,子程序export并不能使变量变成环境变量而在父程序使用。
    • 删除变量使用unset
    • declare作用
      • 语法:declare [+/-][rxi][变量名称=设置值] 或 declare -f

      • 声明变量并设置变量的属性([rix]即为变量的属性)

        • +/- "-"可用来指定变量的属性,"+"则是取消变量所设的属性。但是+a+r无效,无法删除数组和只读属性,可以使用unset删除数组,但是unset不能删除只读变量  
        • -a 设置变量为数组array
        • -A 声明关联数组,可以使用字符串作为数组索引
        • -f 如果后面没有参数的话会列出之前脚本定义的所有函数,如果有参数的话列出以参数命名的函数
        • -F 不显示函数定义
        • -i 设置变量为整数
        • -l 大写字母变小写,这儿是L的小写l,意思是lowercase。不是大写I哦。
        • -r 将变量设置为只读,设置为只读后,只有注销再登录才能恢复变量原来类型。
        • -t 设置跟踪属性,用于跟踪函数进行调试,对于变量没有特殊意义
        • -u 变量值的大写字母变为大写
        • -x 指定的变量会成为环境变量,可供shell以外的程序来使用。
        • -p 显示变量定义的方式和值
      • 用来显示shell函数。若不加上任何参数,则会显示全部的shell变量与函数(与执行set指令的效果相同)。

  4. 使用set 观察所有变量 (含环境变量与自定义变量)

    • PS1:(提示字符的配置)
      • 提示字符是什么?登录后每次敲命令时显示的这部分[root@wangzz shelldemo]$这个便是。为什么显示这样子,便是由PS1变量决定,当然你可以更改。
      • \d :可显示出『星期 月 日』的日期格式,如:"Mon Feb 2"
      • \H :完整的主机名。举例来说,鸟哥的练习机为『www.vbird.tsai
      • \h :仅取主机名在第一个小数点之前的名字,如鸟哥主机则为『www』后面省略
      • \t :显示时间,为 24 小时格式的『HH:MM:SS』
      • \T :显示时间,为 12 小时格式的『HH:MM:SS』
      • \A :显示时间,为 24 小时格式的『HH:MM』
      • \@ :显示时间,为 12 小时格式的『am/pm』样式
      • \u :目前使用者的账号名称,如『root』;
      • \v :BASH 的版本信息,如鸟哥的测试主板本为 3.2.25(1),仅取『3.2』显示
      • \w :完整的工作目录名称,由根目录写起的目录名称。但家目录会以 ~ 取代;
      • \W :利用 basename 函数取得工作目录名称,所以仅会列出最后一个目录名。
      • \# :下达的第几个命令。
      • \$ :提示字符,如果是 root 时,提示字符为 # ,否则就是 $ 啰~(没有故意卖萌,原话是鸟哥说的)
    • $:(关于本 shell 的 PID)
      • echo $$:显示当前shell的PID
    • ?:(关于上个运行命令的回传值)
      • 是什么意思?当我们每运行一个命令后,这个命令都会返回一个运行结果的代码值。一般成功是0,失败是其他值。示例:
        [root@wangzz shelldemo]$ wangzz
        bash: wangzz: command not found
        [root@wangzz shelldemo]$ echo $?
        127
  5. 键盘读取变量

    • 使用read来读取键盘输入的变量。
      • 语法read [-pt] variable
      • -p :后面可以接提示字符
      • -t :后面可以接等待的时间(秒)
  6. declare 与 typeset

    • 若不使用declare或者typeset,变量类型默认为字符串,无法进行数字计算等操作。
    • bash中数字类型变量,只有整数,无浮点数等。
  7. ulimit

    1. 作用:限制用户可以使用的某些资源,如:可以开启的文件数量,可以使用的CPU时间,可以使用的内存总量等。
    2. ulimit [-SHacdfltu] [配额]
      • 选项与参数:
      • -H :hard limit ,严格的配置,必定不能超过这个配置的数值;
      • -S :soft limit ,警告的配置,可以超过这个配置值,但是若超过则有警告信息。 在配置上,通常 soft 会比 hard 小,举例来说,soft 可配置为 80 而 hard 配置为 100,那么你可以使用到 90 (因为没有超过 100),但介于 80~100 之间时, 系统会有警告信息通知你!
      • -a :后面不接任何选项与参数,可列出所有的限制额度;
      • -c :当某些程序发生错误时,系统可能会将该程序在内存中的信息写成文件(除错用), 这种文件就被称为核心文件(core file)。此为限制每个核心文件的最大容量。
      • -f :此 shell 可以创建的最大文件容量(一般可能配置为 2GB)单位为 Kbytes
      • -d :程序可使用的最大断裂内存(segment)容量;
      • -l :可用于锁定 (lock) 的内存量
      • -t :可使用的最大 CPU 时间 (单位为秒)
      • -u :单一用户可以使用的最大程序(process)数量。
      • -n :同时开启的文件数量
      • ...
  8. 变量内容的删除、取代与替换(所有都只是显示,不改变变量内容,除了使用=

    1. 从匹配到的前往后删除#
      • 语法:echo ${path#/*:},删除匹配的最短的那个。可以使用*匹配所有。
      • # :符合取代文字的『最短的』那一个;
      • ##:符合取代文字的『最长的』那一个
    2. 从匹配到的最后一个往前删除%
      • 语法:echo ${path%:*bin}
      • 注意:和上面的写法除了#变成%外,其他不变。我开始写时候,匹配的字符也是从后往前写,结果删除不掉。
      • % :符合取代文字的『最短的』那一个;
      • %%:符合取代文字的『最长的』那一个
    3. 替换
      • 替换第一处:echo {path/bin/BIN}
      • 替换全部:echo {path//bin/BIN}
    4. 变量值判断后替换
      • new_var=${old_var-content} :如果变量不存在用content替换,如果存在则使用原来值。
      • username=${username:-root} :如果变量不存在或者为空字符串,则替换。否则使用原来值。
    5. 变量不存在报错:
      • echo ${var?error}
    6. +与上面4的-相反
    7. 使用=可以实际地替换变量值。wangzz=${str=newStr}

Bash Shell 的操作环境

  1. 命令运行的顺序

    1. 以相对/绝对路径运行命令,例如『 /bin/ls 』或『 ./ls 』
    2. 由 alias 找到该命令来运行
    3. 由 bash 内建的 (builtin) 命令来运行;
    4. 透过 $PATH 这个变量的顺序搜寻到的第一个命令来运行
  2. bash 的进站与欢迎信息: /etc/issue, /etc/motd

    1. issue 内的各代码意义
      • \d 本地端时间的日期;
      • \l 显示第几个终端机接口;
      • \m 显示硬件的等级 (i386/i486/i586/i686...);
      • \n 显示主机的网络名称;
      • \o 显示 domain name;
      • \r 操作系统的版本 (相当于 uname -r)
      • \t 显示本地端时间的时间;
      • \s 操作系统的名称;
      • \v 操作系统的版本。
    2. motd是 登陆后提供的一些信息
  3. bash 的环境配置文件

    1. login 与 non-login shell

      1. login shell:取得 bash 时需要完整的登陆流程的,就称为 login shell。
      2. non-login shell:取得 bash 接口的方法不需要重复登陆的举动。比如直接bash,回车。
    2. login shell 会读取的两个配置文件:

      1. /etc/profile:系统整体的配置,不要乱修改;同时该文件也会读取其他的配置文件。
        • PATH:会依据 UID 决定 PATH 变量要不要含有 sbin 的系统命令目录;
        • MAIL:依据账号配置好使用者的 mailbox 到 /var/spool/mail/账号名;
        • USER:根据用户的账号配置此一变量内容;
        • HOSTNAME:依据主机的 hostname 命令决定此一变量内容;
        • HISTSIZE:历史命令记录笔数。
      2. ~/.bash_profile 或 ~/.bash_login 或 ~/.profile:属于使用者的配置,你要改自己的数据,就写入这里! bash 的 login shell 配置只会读取上面三个文件的其中一个, 而读取的顺序则是依照上面的顺序。也就是说如果第一个文件存在,其他的不管存在不存在都不会读取。
        • 查看.bash_profile可以发现,里面会判断家目录下的 ~/.bashrc 存在否,若存在则读入 /.bashrc 的配置。所以可以将自己的偏好设置放到/.bashrc中。
    3. source :读入环境配置文件的命令

      • source可以不用注销再登录,就可以将配置生效。
      • .点也可以使配置立即生效。. ~/.bashrc
    4. ~/.bashrc (non-login shell 会读)

    5. 终端机的环境配置: stty, set

      • eof : End of file 的意思,代表『结束输入』。
      • erase : 向后删除字符,
      • intr : 送出一个 interrupt (中断) 的讯号给目前正在 run 的程序;
      • kill : 删除在目前命令列上的所有文字;
      • quit : 送出一个 quit 的讯号给目前正在 run 的程序;
      • start : 在某个程序停止后,重新启动他的 output
      • stop : 停止目前屏幕的输出;
      • susp : 送出一个 terminal stop 的讯号给正在 run 的程序。
    6. bash 环境中的特殊符号

符号 内容
# 批注符号:这个最常被使用在 script 当中,视为说明!在后的数据均不运行
\ 跳脱符号:将『特殊字符或通配符』还原成一般字符
; 连续命令下达分隔符:连续性命令的界定 (注意!与管线命令并不相同)
~ 用户的家目录
$ 取用变量前导符:亦即是变量之前需要加的变量取代值
& 工作控制 (job control):将命令变成背景下工作
! 逻辑运算意义上的『非』 not 的意思!
/ 目录符号:路径分隔的符号
>, >> 数据流重导向:输出导向,分别是『取代』与『累加』
<, << 数据流重导向:输入导向 (这两个留待下节介绍)
' ' 单引号,不具有变量置换的功能
" " 具有变量置换的功能!
两个『 ` 』中间为可以先运行的命令,亦可使用 $( )
( ) 在中间为子 shell 的起始与结束
{ } 在中间为命令区块的组合!

数据流重导向

  1. 什么是数据流重导向?
    1. 通常我们运行一个命令,这个命令可能回从文件读取数据,经过处理后,再将数据输出到屏幕上。数据流重导向就是将某个命令运行后应该要出现在屏幕上的数据,给他传输到其他的地方,例如文件或者是装置 (例如打印机之类的)!
      • 标准输出与标准错误输出:标准输出是命令运行后输出的正确信息,显然另一个是输出的错误信息。
      • 有关代码与字符
        1. 标准输入  (stdin) :代码为 0 ,使用 < 或 << ;
        2. 标准输出  (stdout):代码为 1 ,使用 > 或 >> ;
          • > 会将内容覆盖
          • >> 不会覆盖,会追加内容
        3. 标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ;
          • 追加或者覆盖情况与标准输出一样
      • /dev/null用法(控设备,鸟哥称为垃圾桶黑洞装置)
      • 特殊写法:标准输出与标准错误输出写入同一文件: 2>&1或者&>
        • find /home -name .bashrc > list 2>&1
        • find /home -name .bashrc &> list
      • 标准输入<<<
        • 是什么?

          将原本需要由键盘输入的数据,改由文件内容来取代

        • 使用cat来创建文件cat > file_name,之后输入文件内容,完成后Ctrl+d。
        • 使用别的文件内容来替代键盘输入:cat > filename < src_file
        • <<又是做什么的额?表示输入的结束字符,可以替代Ctrl+d。cat > catfile << "eof"
  2. 命令运行的判断依据: ; , &&, ||
    1. cmd ; cmd (不考虑命令相关性的连续命令下达)就是说两个命令没有关联,只是依次执行两个命令而已。
      • 在命令与命令中间利用分号 (;) 来隔开,这样一来,分号前的命令运行完后就会立刻接着运行后面的命令了。
    2. $? (命令回传值) 与 && 或 ||
      前后运行的命令有相关性,如第二个命令运行是否运行正确来判断第二个命令是否要运行。每个命令运行完成会有个返回值,依据就是这个返回值。类似编程里面的短路概念。
      • cmd1 && cmd2
        1. 若 cmd1 运行完毕且正确运行($?=0),则开始运行 cmd2。
        2. 若 cmd1 运行完毕且为错误 ($?≠0),则 cmd2 不运行。
      • cmd1 || cmd2
        1. 若 cmd1 运行完毕且正确运行($?=0),则 cmd2 不运行。
        2. 若 cmd1 运行完毕且为错误 ($?≠0),则开始运行 cmd2。

管线(管道)命令 (pipe)

  1. 例子:ls -al|less

  2. 管线命令|仅能处理经由前面一个命令传来的正确信息,也就是 standard output 的信息,对于 stdandard error 并没有直接处理的能力。管道后面必须接一个可以接受标准输入的命令。如: less, more, head, tail

    1. 管道命令仅会处理 standard output,对于 standard error output 会予以忽略
    2. 管道命令必须要能够接受来自前一个命令的数据成为 standard input 继续处理才行
  3. 截取命令cut,grep。截取命令通常是针对一行来分析,并非全文。

    1. cut
      • -d :后面接分隔字符。与 -f 一起使用;
      • -f :依据 -d 的分隔字符将一段信息分割成为数段,用 -f 取出第几段的意思;
      • -c :以字符 (characters) 的单位取出固定字符区间;
      • 例子:last|cut -d ' ' -f 1export|head -n 1|cut -c 12-18
    2. grep解析一行文字,取得关键词,若该行有存在关键词,就会整行列出来!
      1. grep [-acinv] [--color=auto] '搜寻字符串' filename
        • -a :将 binary 文件以 text 文件的方式搜寻数据
        • -c :计算找到 '搜寻字符串' 的次数
        • -i :忽略大小写的不同,所以大小写视为相同
        • -n :顺便输出行号
        • -v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行!
        • --color=auto :可以将找到的关键词部分加上颜色的显示喔
      2. 例子:grep -i 'manpath' /etc/man_db.conf
  4. 排序命令sort, wc, uniq

    1. sort [-fbMnrtuk] [file or stdin] 依据不同的数据型态来排序

      • -f :忽略大小写的差异,例如 A 与 a 视为编码相同;
      • -b :忽略最前面的空格符部分;
      • -M :以月份的名字来排序,例如 JAN, DEC 等等的排序方法;
      • -n :使用『纯数字』进行排序(默认是以文字型态来排序的);
      • -r :反向排序;
      • -u :就是 uniq ,相同的数据中,仅出现一行代表;
      • -t :分隔符,默认是用 [tab] 键来分隔;
      • -k :以那个区间 (field) 来进行排序的意思
      • 例子:cat /etc/passwd | sort -t ':' -k 3
    2. uniq [-ic]将重复的行删除掉只显示一个

      • -i :忽略大小写字符的不同;
      • -c :进行计数
    3. wc [-lwm]

      • -l :仅列出行;
      • -w :仅列出多少字(英文单字);
      • -m :多少字符;
  5. 双向重导向: tee [-a] file

    • tee 会同时将数据流分送到文件去与屏幕 (screen);而输出到屏幕的,其实就是 stdout ,可以让下个命令继续处理喔!
  6. 字符转换命令: tr, col, join, paste, expand

    1. tr - translate or delete characters替换或者删除字符串。

      • tr [-ds] SET1 ...
        • -d :删除信息当中的 SET1 这个字符串;
        • -s :取代掉重复的字符!
      • 例子:cat passwd |tr -d '\r' > ~/passwd.linux
    2. col - filter reverse line feeds from input

      • col [-xb]
        • -x :将 tab 键转换成对等的空格键
        • -b :在文字内有反斜杠 (/) 时,仅保留反斜杠最后接的那个字符
      • 例子```cat testChar.c|col -x|cat -A``
    3. join - join lines of two files on a common field

      • join [-ti12] file1 file2
        • -t :join 默认以空格符分隔数据,并且比对『第一个字段』的数据, 如果两个文件相同,则将两笔数据联成一行,且第一个字段放在第一个!
        • -i :忽略大小写的差异;
        • -1 :这个是数字的 1 ,代表『第一个文件要用那个字段来分析』的意思;
        • -2 :代表『第二个文件要用那个字段来分析』的意思。
    4. paste - merge lines of files

      • 将两行贴在一起,且中间以 [tab] 键隔开
      • paste [-d] file1 file2
        • -d :后面可以接分隔字符。默认是以 [tab] 来分隔的!
        • - :如果 file 部分写成 - ,表示来自 standard input 的数据的意思
      • 例子:cat /etc/group|paste /etc/passwd /etc/shadow -|head -n 3
    5. expand - convert tabs to spaces

      • 将tab按键转成空格键(ps:这不就是col -x 吗)
      • expand [-t] file
        • -t :后面可以接数字。一般来说,一个 tab 按键可以用 8 个空格键取代。 我们也可以自行定义一个 [tab] 按键代表多少个字符呢!
      • 例子:grep '^MANPATH' /etc/man_db.conf |head -n 3|expand -t 1|cat -A,注意这儿添加多少空格并不是死值。
  7. 分割命令: split

    • split - split a file into pieces
    • 依据文件大小或者行数来分割文件。
    • split [-bl] file PREFIX
      • -b :后面可接欲分割成的文件大小,可加单位,例如 b, k, m 等;
      • -l :以行数来进行分割。
    • PREFIX :代表前导符的意思,可作为分割文件的前导文字。
    • 例子:ls -al / | split -l 10 - lsroot,这里注意,如果你忽略了-,也就是这样输入ls -al|split -l 10 lsroot.,你会得到这个错误:split: cannot open ‘ls.’ for reading: No such file or directory。因为这里没有文件,这里的 - 就会被当成 stdin 或 stdout。
  8. 参数替换xargs

    • xargs - build and execute command lines from standard input
    • xargs [-0epn] command
      • -0 :如果输入的 stdin 含有特殊字符,例如 `, , 空格键等等字符时,这个 -0 参数 可以将他还原成一般字符。这个参数可以用于特殊状态喔!
      • -e :这个是 EOF (end of file) 的意思。后面可以接一个字符串,当 xargs 分析到 这个字符串时,就会停止继续工作!
      • -p :在运行每个命令的 argument 时,都会询问使用者的意思;
      • -n :后面接次数,每次 command 命令运行时,要使用几个参数的意思。看范例三。
      • 当 xargs 后面没有接任何的命令时,默认是以 echo 来进行输出!
    • 例子:find /sbin -perm +7000 | xargs ls -lfind ./ -name "*" |xargs -p grep -n "ab"
  9. 关于减号 - 的用途

    1. 上面提到-可以当成 stdin 或 stdout。某些命令需要用到文件名 (例如 tar) 来进行处理时,该 stdin 与 stdout 可以利用减号 "-" 来替代, 举例来说:
      • [root@www ~]# tar -cvf - /home | tar -xvf -

正则表达式(鸟哥称为正规表达式)

鸟哥这里用了很大的篇幅介绍正则表达式,这儿大多数编程语言学习时候都会进行学习,所以不做重点学习,大概预览一下。

文件的格式化与相关处理