Linux的Bash

风尘

文章目录

  1. 1. Shell
  2. 2. Bash shell 功能
    1. 2.1. 命令编修能力
    2. 2.2. type指令
    3. 2.3. 快速编辑
    4. 2.4. 变量
      1. 2.4.1. echo 指令
      2. 2.4.2. 变量设置规则
      3. 2.4.3. 环境变量
      4. 2.4.4. 语系变量
      5. 2.4.5. 变量范围
      6. 2.4.6. 变量键盘读取/阵列与宣告
      7. 2.4.7. 变量内容删除/取代/替换
    5. 2.5. 系统限制关系 ulimit
    6. 2.6. 命令别名与历史命令
      1. 2.6.1. 别名设置 alias / unalias
      2. 2.6.2. 历史命令 history
  3. 3. Bash Shell操作环境
    1. 3.1. Bash 进站欢迎信息 /etc/issue /etc/motd
    2. 3.2. bash环境配置文件
      1. 3.2.1. login与non-login Shell
      2. 3.2.2. /etc/profile (login Shell读取)
      3. 3.2.3. ~/.bash_profile (login Shell读取)
      4. 3.2.4. source 读入环境配置文件指令
      5. 3.2.5. ~/.bashrc (non-login shell 读取)
    3. 3.3. 终端机环境设置 stty , set
      1. 3.3.1. stty命令
      2. 3.3.2. set命令
    4. 3.4. 万用字符与特殊符号
  4. 4. 数据流重导向
    1. 4.1. 数据流输入/输出
      1. 4.1.1. /dev/null 垃圾桶黑洞设备与特殊写法
      2. 4.1.2. 2>& | &>
      3. 4.1.3. 标准输入
    2. 4.2. 命令执行的判断依据 ; && ||
      1. 4.2.1. 不考虑指令相关性的连续指令下达 cmd;cmd
      2. 4.2.2. $? (指令回传值) 与 && 或 ||
  5. 5. 管线命令(pipe)
    1. 5.1. 撷取命令 cut grep
      1. 5.1.1. cut
      2. 5.1.2. grep
    2. 5.2. 排序命令 sort wc uniq
      1. 5.2.1. sort
      2. 5.2.2. uniq
      3. 5.2.3. wc
    3. 5.3. 双重导向tee
    4. 5.4. 字符转换命令 tr, col, join, paste, expand
      1. 5.4.1. tr
      2. 5.4.2. col
    5. 5.5. 分区命令 split
    6. 5.6. 参数代换 xargs(后面貌似不能用alias)
    7. 5.7. 减号 " - " 的用途

[TOC]

Shell

/etc/shells记录系统所有shell

Bash shell 功能

命令编修能力

默认指令记忆功能可以达到1000个
记录位置~/.bash_history(当前指令用户指令在内存中,登出后才记录到文件此内)

  • 命令与文件实例功能(tab补全)
  • 命令别名设置功能
  • 工作控制/前景背景控制
  • 程序化脚本shell script
  • 万用字符(*)

type指令

type 这个指令我们可以知道每个指令是否为 bash 的内置指令。 此外,type只能查找可执行文件.

1
2
3
4
5
6
7
8
9
[dmtsai@study ~]$ type [-tpa] name
选项与参数:
:不加任何选项与参数时,type 会显示出 name 是外部指令还是 bash 内置指令
-t :当加入 -t 参数时,type 会将 name 以下面这些字眼显示出他的意义:
file :表示为外部指令;
alias :表示该指令为命令别名所设置的名称;
builtin :表示该指令为 bash 内置的指令功能;
-p :如果后面接的 name 为外部指令时,才会显示完整文件名;
-a :会由 PATH 变量定义的路径中,将所有含 name 的指令都列出来,包含 alias

快速编辑

  • 反斜杠( \ )
    命令输入太长需要换行,利用反斜杠( \ )[Enter]开启下一行,而不执行命令.
    注意: [Enter] 按键是紧接着反斜线 ( \ )

  • 快捷键

组合键 功能与示范
[ctrl]+u/[ctrl]+k 分别是从光标处向前删除指令串 ([ctrl]+u) 及向后删除指令串 ([ctrl]+k)
[ctrl]+a/[ctrl]+e 分别是让光标移动到整个指令串的最前面 ([ctrl]+a) 或最后面 ([ctrl]+e)
Ctrl + C 终止目前命令
Ctrl + D 输入结束(EOF),例如:邮件结束的时候
Ctrl + M 就是Enter
Ctrl + S 暂停屏幕输出
Ctrl + Q 恢复屏幕输出
Ctrl + U 在提示字符下,将整列命令删除
Ctrl + Z “暂停”目前的命令 配合fg/bg/jobs命令使用

变量

echo 指令

显示变量内容,"-e"选项可以格式化打印内容

1
[dmtsai@study ~]$ echo $PATH

变量设置规则

  1. 变量与变量内容以一个"="来连接.
    myname=Windus

  2. 等号两边不能直接接空白符.

    1
    2
    3
    #错误
    myname= Windus
    myname=Windus L
  3. 变量内容若有空白符可使用双引号或单引号将变量内容结合起来.

    1
    2
    3
    4
    5
    6
    7
    #双引号内特殊字符可保持原本特性,如:"$"等
    var="lang is $LANG"
    echo $var --> lang is UTF8

    #单引号内的特殊字符仅为一般字符(纯文本)
    var='lang is $LANG'
    echo $var --> lang is $LANG
  4. 变量名称只能是英文字母与数字,但开头字符不能是数字.

  5. 可用跳脱字符" \ ",将特殊符号变成一般符号。(如: [Enter], $, , 空白字符等)

    myname=Windus\ L

  6. 在一串指令的执行中,还需要借由其他额外的指令所提供的信息时,可以使用反单引号“指令”或 “$(指令)

    1
    2
    version=$(uname -r)
    echo $version --> 3.10.0-229.el7.x86_64
  7. 若该变量为扩增变量内容时,则可用 “$变量名称” 或 ${变量} 累加内容

    1
    2
    3
    PATH="$PATH":/home/bin

    PATH=${PATH}:/home/bin
  8. 若该变量需要在其他子程序执行,则需要以 export 来使变量变成环境变量
    export PATH

  9. 通常大写字符为系统默认变量,自行设置变量可以使用小写字符,方便判断 (纯粹依照使用者兴趣与嗜好,在 Linux 默认的情况中,使用{大写的字母}来设置的变量一般为系统内定需要的变量)

  10. 取消变量用unset
    unset myname

环境变量

  • env命令
    查看所有环境变量

    • HOME 使用者主文件夹变量, ~就会读取此变量

    • SHELL 目前环境使用的SHELL程序(Linux默认:/bin/bash)

    • HISTSIZE 历史命令记录笔数

    • MAIL 当前用户邮箱文件

    • PATH 可执行文件搜寻的路径(目录与目录中间:分隔).由于搜寻顺序依据PATH变量内目录顺序,所以目录顺序也是重要的.

    • LANG 语系数据

    • RANDOM 随机数变量(/dev/random),内容介于0~32767之间.

      1
      2
      3
      4
      #想要获取指定范围内的数,使用delcare声名数值类型
      [dmtsai@study ~]$ declare -i number=$RANDOM*10/32768 ;
      echo $number
      8 <== 此时会随机取出 0~9 之间的数值喔!
  • set命令
    查看所有变量(含环境变量与自定变量)

    • PS1 提示字符的设置

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      \d :可显示出“星期 月 日”的日期格式,如:"Mon Feb 2"
      \H :完整的主机名称。举例来说,鸟哥的练习机为“study.centos.vbird”
      \h :仅取主机名称在第一个小数点之前的名字,如鸟哥主机则为“study”后面省略
      \t :显示时间,为 24 小时格式的“HH:MM:SS”
      \T :显示时间,为 12 小时格式的“HH:MM:SS”
      \A :显示时间,为 24 小时格式的“HH:MM”
      \@ :显示时间,为 12 小时格式的“am/pm”样式
      \u :目前使用者的帐号名称,如“dmtsai”;
      \v :BASH 的版本信息,如鸟哥的测试主机版本为 4.2.46(1)-release,仅取“4.2”显示
      \w :完整的工作目录名称,由根目录写起的目录名称。但主文件夹会以 ~ 取代;
      \W :利用 basename 函数取得工作目录名称,所以仅会列出最后一个目录名。
      \# :下达的第几个指令。
      \$ :提示字符,如果是 root 时,提示字符为 # ,否则就是 $
    • $ 本shell的PID
      echo $$

    • ? 上个指令的回传值
      执行某些指令时, 这些指令都会回传一个执行后的代码。一般来说,如果成功的执行该指令, 则会回传一个 0 值,如果执行过程发生错误,就会传回错误代码.一般以非0代码取代.

  • export命令
    当你登陆 Linux 并取得一个 bash 之后,你的 bash 就是一个独立的程序,这个程序的识别使用的是一个称为程序识别码,被称为 PID 的就是。 接下来你在这个 bash 下面所下达的任何指令都是由这个 bash 所衍生出来的,那些被下达的指令就被称为子程序了.
    程序相关性示意图程序相关性示意图

    子程序仅会继承父程序的环境变量, 子程序不会继承父程序的自订变量.所以你在原本 bash 的自订变量在进入了子程序后就会消失不见, 一直到你离开子程序并回到原本的父程序后,这个变量才会又出现!
    此时,把自定变量变成环境变量就变得很有必要了:
    export 变量名称

如果export后面不加变量名称,就会将系统所有变量列出来,等同于set命令.

语系变量

  • 查看Linux支持的语系

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [dmtsai@study ~]$ locale -a
    ....(前面省略)....
    zh_TW
    zh_TW.big5 <==大五码的中文编码
    zh_TW.euctw
    zh_TW.utf8 <==万国码的中文编码
    zu_ZA
    zu_ZA.iso88591
    zu_ZA.utf8
  • 修改Linux语系

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    locale  <==后面不加任何选项与参数即可!
    LANG=en_US <==主语言的环境
    LC_CTYPE="en_US" <==字符(文字)辨识的编码
    LC_NUMERIC="en_US" <==数字系统的显示讯息
    LC_TIME="en_US" <==时间系统的显示数据
    LC_COLLATE="en_US" <==字串的比较与排序等
    LC_MONETARY="en_US" <==币值格式的显示等
    LC_MESSAGES="en_US" <==讯息显示的内容,如功能表、错误讯息等
    LC_ALL= <==整体语系的环境
    ....(后面省略)....

    可以逐一设置每个与语系有关的变量数据,可也以直接设置LANG或LC_ALL(其它语系变量会被这两个变量所取代).

    系统默认语系文件是: /etc/locale.conf

变量范围

环境变量可以被子程序引用的原理:

  1. 当启动一个shell,系统会分配一个记忆区给shell使用,使此内存内的变量,即环境变量可让子程序使用.
  2. 若父程序用export功能,将自定变量内容写到上述内存区块当中(环境变量).
  3. 当载入另一个shell时(亦启动一个子程序,离开原本父程序),子程序可以将父shell的环境变量所在记忆区导入自己的环境变量区块当中.

变量键盘读取/阵列与宣告

  • read命令
    程序执行的过程当中,会等待使用者输入 “yes/no” 之类的讯息,和使用者对谈时使用此命令.

    1
    2
    3
    4
    [dmtsai@study ~]$ read [-pt] variable
    选项与参数:
    -p :后面可以接提示字符!
    -t :后面可以接等待的“秒数!”这个比较有趣~不会一直等待使用者啦!
  • declare/typeset
    declare 或 typeset 是一样的功能,就是在“宣告变量的类型.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [dmtsai@study ~]$ declare [-aixr] variable
    选项与参数:
    -a :将后面名为 variable 的变量定义成为阵列 (array) 类型
    -i :将后面名为 variable 的变量定义成为整数数字 (integer) 类型
    -x :用法与 export 一样,就是将后面的 variable 变成环境变量;
    -r :将变量设置成为 readonly 类型,该变量不可被更改内容,也不能 unset
    -p : 仅列出变量类型

    范例一:让变量 sum 进行 100+300+50 的加总结果
    [dmtsai@study ~]$ sum=100+300+50
    [dmtsai@study ~]$ echo ${sum}
    100+300+50 <==咦!怎么没有帮我计算加总?因为这是文字体态的变量属性啊!
    [dmtsai@study ~]$ declare -i sum=100+300+50
    [dmtsai@study ~]$ echo ${sum}
    450 <==瞭乎??

注意: bash环境下,变量类型默认为“字串”,所以若不指定变量类型,则 1+2 为一个“字串”而不是“计算式”。 所以上述第一个执行的结果才会出现那个情况的;
bash 环境中的数值运算,默认最多仅能到达整数形态,所以 1/3 结果是 0;

变量内容删除/取代/替换


暂时跳过


系统限制关系 ulimit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[dmtsai@study ~]$ 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 <文件数目>:指定同一时间最多可开启的文件数;

命令别名与历史命令

别名设置 alias / unalias

1
2
3
4
#设置别名
[dmtsai@study ~]$ alias lm='ls -al | more
#取消别名
[dmtsai@study ~]$ unalias lm

设置别名,在机器重启后将丢失,如果想永久存在,需要写在~/.bash_profile文件内

历史命令 history

历史命令记录在~/.bash_history文件中,记录的数量由HISTFILESIZE环境变量决定.

1
2
3
4
5
6
7
8
[dmtsai@study ~]$ history [-raw] histfiles
选项与参数:
n :数字,意思是“要列出最近的 n 笔命令列表”的意思!
-c :将目前的 shell 中的所有 history 内容全部消除
-a :将目前新增的 history 指令新增入 histfiles 中,若没有加 histfiles ,
则默认写入 ~/.bash_history
-r :将 histfiles 的内容读到目前这个 shell 的 history 记忆中;
-w :将目前的 history 记忆内容写入 histfiles 中!
  • 历史命令的使用:

    1
    2
    3
    4
    5
    [dmtsai@study ~]$ !
    选项与参数:
    number :执行第几笔指令的意思;
    command :由最近的指令向前搜寻“指令串开头为 command”的那个指令,并执行;
    !! :就是执行上一个指令(相当于按↑按键后,按 Enter)
  • 同一帐号同时多次登陆的history写入问题

    因为这些 bash 在同时以同一个身份登陆, 因此所有的 bash 都有自己的 1000 笔记录在内存中。因为等到登出时才会更新记录文件,所以,最后登出的那个 bash 才会是最后写入的数据。如此一来其他 bash 的指令操作就不会被记录下来了 (其实有被记录,只是被后来的最后一个 bash 所覆盖更新了) 。

  • 历史命令时间问题
    历史命令还有一个问题,那就是无法记录指令下达的时间。由于这 1000 笔历史命令是依序记录的, 但是并没有记录时间,所以在查询方面会有一些不方便。其实可以通过~/.bash_logout 来进行 history 的记录,并加上 date 来增加时间参数.

Bash Shell操作环境

Bash 进站欢迎信息 /etc/issue /etc/motd

1
2
3
4
5
6
7
8
9
10
issue 内的各代码意义:
\d 本地端时间的日期;
\l 显示第几个终端机接口;
\m 显示硬件的等级 (i386/i486/i586/i686...);
\n 显示主机的网络名称;
\O 显示 domain name;
\r 操作系统的版本 (相当于 uname -r)
\t 显示本地端时间的时间;
\S 操作系统的名称;
\v 操作系统的版本

当我们使用 telnet 连接到主机时,主机的登陆画面就会显示 /etc/issue.net 而不是 /etc/issue
/etc/motd 里面显示的则是文字信息

bash环境配置文件

login与non-login Shell

  • login shell:取得 bash 时需要完整的登陆流程的,就称为 login shell。举例来说,你要由 tty1 ~ tty6 登陆,需要输入使用者的帐号与密码,此时取得的 bash 就称为“ login shell ”

  • non-login shell:取得 bash 接口的方法不需要重复登陆的举动,举例来说,(1)你以 X window 登陆 Linux 后, 再以 X 的图形化接口启动终端机,此时那个终端接口并没有需要再次的输入帐号与密码,那个 bash 的环境就称为 non-login shell了。(2)你在原本的 bash 环境下再次下达 bash 这个指令,同样的也没有输入帐号密码, 那第二个 bash (子程序) 也是 non-login shell 。

这两个Shell,读取的配置文件数据并不一样.

/etc/profile (login Shell读取)

这个配置文件可以利用使用者的识别码 (UID) 来决定很多重要的变量数据, 也是每个使用者登陆取得 bash 时一定会读取的配置文件.所以设置全局环境就要改这个文件!

1
2
3
4
5
6
7
主要变量:
PATH:会依据 UID 决定 PATH 变量要不要含有 sbin 的系统指令目录;
MAIL:依据帐号设置好使用者的 mailbox 到 /var/spool/mail/帐号名;
USER:根据使用者的帐号设置此一变量内容;
HOSTNAME:依据主机的 hostname 指令决定此一变量内容;
HISTSIZE:历史命令记录笔数。CentOS 7.x 设置为 1000 ;
umask:包括 root 默认为 022 而一般用户为 002 等!

/etc/profile 还会调用外部的设置数据,主要有如下:

  • /etc/profile.d/*.sh
    “这个目录内的众多文件!只要在 /etc/profile.d/ 这个目录内且扩展名为 .sh ,另外,使用者能够具有 r 的权限, 那么该文件就会被 /etc/profile 调用进来。在 CentOS 7.x 中,这个目录下面的文件规范了 bash 操作接口的颜色、 语系、ll 与 ls 指令的命令别名、vi 的命令别名、which 的命令别名等等。如果你需要帮所有使用者设置一些共享的命令别名时, 可以在这个目录下面自行创建扩展名为 .sh 的文件,并将所需要的数据写入即可!

  • /etc/locale.conf
    这个文件是由 /etc/profile.d/lang.sh 调用进来的!这也是我们决定 bash 默认使用何种语系的重要配置文件! 文件里最重要的就是 LANG/LC_ALL 这些个变量的设置!

  • /usr/share/bash-completion/completions/*
    这个目录下除前面谈过 [tab] 命令补齐、文件名补齐之外,还可以进行指令的选项/参数补齐功能!那就是从这个目录里面找到相对应的指令来处理的! 其实这个目录下面的内容是由 /etc/profile.d/bash_completion.sh 这个文件载入的啦!

~/.bash_profile (login Shell读取)

bash 在读完了整体环境设置的 /etc/profile 并借此调用其他配置文件后,接下来则是会读取使用者的个人配置文件。 在 login shell 的 bash 环境中,所读取的个人偏好配置文件其实主要有三个,依序分别是:

1
2
3
1. ~/.bash_profile
2. ~/.bash_login
3. ~/.profile

其实 bash 的 login shell 设置只会读取上面三个文件的其中一个, 而读取的顺序则是依照上面的顺序。也就是说,如果 ~/.bash_profile 存在,那么其他两个文件不论有无存在,都不会被读取。 如果 ~/.bash_profile 不存在才会去读取 ~/.bash_login,而前两者都不存在才会读取 ~/.profile 的意思。 会有这么多的文件,其实是因应其他 shell 转换过来的使用者的习惯而已。

shell 读取流程shell 读取流程

source 读入环境配置文件指令

由于 /etc/profile 与 ~/.bash_profile 都是在取得 login shell 的时候才会读取的配置文件,所以, 如果你将自己的偏好设置写入上述的文件后,通常都是得登出再登陆后,该设置才会生效。利用这个指令可以直接生效!

1
2
3
4
5
[dmtsai@study ~]$ source 配置文件文件名

范例:将主文件夹的 ~/.bashrc 的设置读入目前的 bash 环境中
[dmtsai@study ~]$ source ~/.bashrc <==下面这两个指令是一样的!
[dmtsai@study ~]$ . ~/.bashrc

~/.bashrc (non-login shell 读取)

CentOS 7.x 还会主动的调用 /etc/bashrc 这个文件

1
2
3
4
/etc/bashrc文件记录内容
1. 依据不同的 UID 规范出 umask 的值;
2. 依据不同的 UID 规范出提示字符 (就是 PS1 变量);
3. 调用 /etc/profile.d/*.sh 的设置

/etc/bashrc文件是Red Hat系统特有的,如果此文件丢失,可以复制 /etc/skel/.bashrc 到你的主文件夹.

终端机环境设置 stty , set

stty命令

查阅目前的一些按键内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[dmtsai@study ~]$ stty [-a]
选项与参数:
-a :将目前所有的 stty 参数列出来;

#列出所有的按键与按键内容
[dmtsai@study ~]$ stty -a
speed 38400 baud; rows 20; columns 90; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
flush = ^O; min = 1; time = 0;
....(以下省略)....

#设置按键
[dmtsai@study ~]$ stty erase ^h

意义:
intr  : 送出一个 interrupt (中断) 的讯号给目前正在 执行的程序 (就是终止啰!);
quit  : 送出一个 quit 的讯号给目前正在执行的程序;
erase : 向后删除字符,
kill  : 删除在目前命令行上的所有文字;
eof   : End of file 的意思,代表“结束输入”。
start : 在某个程序停止后,重新启动他的 output
stop  : 停止目前屏幕的输出;
susp  : 送出一个 terminal stop 的讯号给正在 run 的程序。

set命令


暂无


万用字符与特殊符号

万用字符:

1
2
3
4
5
6
7
*	代表“ 0 个到无穷多个”任意字符
? 代表“一定有一个”任意字符
[] 同样代表“一定有一个在括号内”的字符(非任意字符)。例如 [abcd] 代表“一定有一个字符, 可能是 a, b, c, d 这四个任何一个”

[-] 若有减号在中括号内时,代表“在编码顺序内的所有字符”。例如 [0-9] 代表 0 到 9 之间的所有数字,因为数字的语系编码是连续的!

[^] 若中括号内的第一个字符为指数符号 (^) ,那表示“反向选择”,例如 [^abc] 代表 一定有一个字符,只要是非 a, b, c 的其他字符就接受的意思。

特殊字符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#	注解符号:这个最常被使用在 script 当中,视为说明!在后的数据均不执行
\ 跳脱符号:将“特殊字符或万用字符”还原成一般字符
| 管线 (pipe):分隔两个管线命令的界定(后两节介绍);
; 连续指令下达分隔符号:连续性命令的界定 (注意:与管线命令并不相同)
~ 使用者的主文件夹
$ 取用变量前置字符:亦即是变量之前需要加的变量取代值
& 工作控制 (job control):将指令变成背景下工作
! 逻辑运算意义上的“非” not 的意思!
/ 目录符号:路径分隔的符号
>, >> 数据流重导向:输出导向,分别是“取代”与“累加”
<, << 数据流重导向:输入导向
'' 单引号,不具有变量置换的功能 ($ 变为纯文本)
"" 具有变量置换的功能! ($ 可保留相关功能)
`` 两个“ ` ”中间为可以先执行的指令,亦可使用 $( )
() 在中间为子 shell 的起始与结束
{} 在中间为命令区块的组合!

数据流重导向

数据流输入/输出

标准输出:指的是“指令执行所回传的正确的讯息”
标准错误输出:“ 指令执行失败后,所回传的错误讯息”

标准输入  (stdin) :代码为 0 ,使用 < 或 << ;
标准输出  (stdout):代码为 1 ,使用 > 或 >> ;
标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ;

/dev/null 垃圾桶黑洞设备与特殊写法

/dev/null 可以吃掉任何导向这个设备的信息

2>& | &>

1
2
3
#将指令的数据全部写入名为 list 的文件中(包括错误信息)
[dmtsai@study ~]$ find /home -name .bashrc > list 2>&1
[dmtsai@study ~]$ find /home -name .bashrc &> list

标准输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#利用 cat 指令来创建一个文件的简单流程
[dmtsai@study ~]$ cat > catfile
testing
cat file test
<==这里按下 [ctrl]+d 来离开

[dmtsai@study ~]$ cat catfile
testing
cat file test

#用 stdin 取代键盘的输入以创建新文件的简单流程
[dmtsai@study ~]$ cat > catfile < ~/.bashrc
[dmtsai@study ~]$ ll catfile ~/.bashrc
# 注意看,这两个文件的大小会一模一样!几乎像是使用 cp 来复制一般!
-rw-r--r--. 1 dmtsai dmtsai 231 Mar 6 06:06 /home/dmtsai/.bashrc
-rw-rw-r--. 1 dmtsai dmtsai 231 Jul 9 18:58 catfile


#用 cat 直接将输入的讯息输出到 catfile 中, 且当由键盘输入 eof 时,该次输入就结束
[dmtsai@study ~]$ cat > catfile << "eof"
> This is a test.
> OK now stop
> eof <==输入这关键字,立刻就结束而不需要输入 [ctrl]+d

[dmtsai@study ~]$ cat catfile
This is a test.
OK now stop <==只有这两行,不会存在关键字那一行!

命令执行的判断依据 ; && ||

不考虑指令相关性的连续指令下达 cmd;cmd

1
[root@study ~]# sync; sync; shutdown -h now

$? (指令回传值) 与 && 或 ||

若前一个指令执行的结果为正确,在 Linux 下面会回传一个 $? = 0 的值

指令 说明
cmd1 && cmd2 1. 若 cmd1 执行完毕且正确执行($?=0),则开始执行 cmd2。
2. 若 cmd1 执行完毕且为错误 ($?≠0),则 cmd2 不执行。
cmd1 || cmd2 1. 若 cmd1 执行完毕且正确执行($?=0),则 cmd2 不执行。
2. 若 cmd1 执行完毕且为错误 ($?≠0),则开始执行 cmd2。
1
[dmtsai@study ~]$ ls /tmp/abc || mkdir /tmp/abc && touch /tmp/abc/hehe

Linux 下面的指令都是由左往右执行,上面执行结果:
情况一:
(1)若 /tmp/abc 不存在故回传 $?≠0,则
(2)因为 || 遇到非为 0 的 $? 故开始 mkdir /tmp/abc,由于 mkdir /tmp/abc 会成功进行,所以回传 $?=0
(3)因为 && 遇到 $?=0 故会执行 touch /tmp/abc/hehe,最终 hehe 就被创建了;

情况二:
(1)若 /tmp/abc 存在故回传 $?=0,则
(2)因为 || 遇到 0 的 $? 不会进行,此时 $?=0 继续向后传,故
(3)因为 && 遇到 $?=0 就开始创建 /tmp/abc/hehe 了!最终 /tmp/abc/hehe 被创建起来。

指令执行关系示意图指令执行关系示意图

1
2
3
4
ls /tmp/vbirding || echo "not exist" && echo "exist”
#返回结果:
not exist
exist

由于指令是一个接着一个去执行的,因此,如果真要使用判断, 那么这个 && 与 || 的顺序就不能搞错(如上面例子).
一般来说,假设判断式有三个,也就是:
command1 && command2 || command3

管线命令(pipe)

管线命令使用的是“ | ”这个界定符号! 另外,管线命令与“连续下达命令”是不一样!
管线命令“ | ”仅能处理经由前面一个指令传来的正确信息,也就是 standard output 的信息,对于 stdandard error 并没有直接处理的能力.
每个管线后面接的第一个数据必定是“指令”喔!而且这个指令必须要能够接受 standard input 的数据才行,这样的指令才可以是为“管线命令”

撷取命令 cut grep

cut

将一段讯息的某一段给他“切”出来~ 处理的讯息是以“行”为单位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[dmtsai@study ~]$ cut -d'分隔字符' -f fields <==用于有特定分隔字符
[dmtsai@study ~]$ cut -c 字符区间 <==用于排列整齐的讯息
选项与参数:
-d :后面接分隔字符。与 -f 一起使用;
-f :依据 -d 的分隔字符将一段讯息分区成为数段,用 -f 取出第几段的意思;
-c :以字符 (characters) 的单位取出固定字符区间;

[dmtsai@study ~]$ echo ${PATH} | cut -d ':' -f 5 #显示切割后的第5个
[dmtsai@study ~]$ echo ${PATH} | cut -d ':' -f 3,5 #显示切割后的3-5个
[dmtsai@study ~]$ echo ${PATH} | cut -d ':' -f 3- #显示切割后的3到最后一个

#将 export 输出的讯息,取得第 12 字符以后的所有字串
[dmtsai@study ~]$ export
declare -x HISTCONTROL="ignoredups"
declare -x HISTSIZE="1000"
declare -x HOME="/home/dmtsai"
declare -x HOSTNAME="study.centos.vbird"
.....(其他省略).....
# 注意看,每个数据都是排列整齐的输出!如果我们不想要“ declare -x ”时,就得这么做:

[dmtsai@study ~]$ export | cut -c 12-
HISTCONTROL="ignoredups"
HISTSIZE="1000"
HOME="/home/dmtsai"
HOSTNAME="study.centos.vbird"
.....(其他省略).....

grep

1
2
3
4
5
6
7
8
9
10
[dmtsai@study ~]$ grep [-acinv] [--color=auto] '搜寻字串' filename
选项与参数:
-a :将 binary 文件以 text 文件的方式搜寻数据
-c :计算找到 '搜寻字串' 的次数
-i :忽略大小写的不同,所以大小写视为相同
-n :顺便输出行号
-v :反向选择,亦即显示出没有 '搜寻字串' 内容的那一行!
--color=auto :可以将找到的关键字部分加上颜色的显示喔!
-A : 后面可加数字,为 after 的意思,除了列出该行外,后续的 n 行也列出来;
-B : 后面可加数字,为 before 的意思,除了列出该行外,前面的 n 行也列出来;

排序命令 sort wc uniq

sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[dmtsai@study ~]$ sort [-fbMnrtuk] [file or stdin]
选项与参数:
-f :忽略大小写的差异,例如 A 与 a 视为编码相同;
-b :忽略最前面的空白字符部分;
-M :以月份的名字来排序,例如 JAN, DEC 等等的排序方法;
-n :使用“纯数字”进行排序(默认是以文字体态来排序的);
-r :反向排序;
-u :就是 uniq ,相同的数据中,仅出现一行代表;
-t :分隔符号,默认是用 [tab] 键来分隔;
-k :以那个区间 (field) 来进行排序的意思


#/etc/passwd 内容是以 : 来分隔的,我想以第三栏来排序,该如何?
[dmtsai@study ~]$ cat /etc/passwd | sort -t ':' -k 3
root:x:0:0:root:/root:/bin/bash
dmtsai:x:1000:1000:dmtsai:/home/dmtsai:/bin/bash
alex:x:1001:1002::/home/alex:/bin/bash
arod:x:1002:1003::/home/arod:/bin/bash
# 看到特殊字体的输出部分了吧?怎么会这样排列啊?呵呵!没错啦~
# 如果是以文字体态来排序的话,原本就会是这样,想要使用数字排序:
# cat /etc/passwd | sort -t ':' -k 3 -n
# 这样才行啊!用那个 -n 来告知 sort 以数字来排序啊!

uniq

重复的数据仅列出一个显示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[dmtsai@study ~]$ uniq [-ic]
选项与参数:
-i :忽略大小写字符的不同;
-c :进行计数

#使用 last 将帐号列出,仅取出帐号栏,进行排序后仅取出一位;
[dmtsai@study ~]$ last | cut -d ' ' -f1 | sort | uniq

#承上,继续显示每个帐号登录次数
[dmtsai@study ~]$ last | cut -d ' ' -f1 | sort | uniq -c
1
6 (unknown
47 dmtsai
4 reboot
7 root
1 wtmp

wc

1
2
3
4
5
6
7
8
9
10
[dmtsai@study ~]$ wc [-lwm]
选项与参数:
-l :仅列出行;
-w :仅列出多少字(英文单字);
-m :多少字符;

#/etc/man_db.conf 里面到底有多少相关字、行、字符数?
[dmtsai@study ~]$ cat /etc/man_db.conf | wc
131 723 5171
# 输出的三个数字中,分别代表: “行、字数、字符数

双重导向tee

可以让 standard output 转存一份到文件内并将同样的数据继续送到屏幕去处理.
tee工作流程示意图tee工作流程示意图

1
2
3
4
5
6
7
8
9
[dmtsai@study ~]$ tee [-a] file
选项与参数:
-a :以累加 (append) 的方式,将数据加入 file 当中!

[dmtsai@study ~]$ ls -l /home | tee ~/homefile | more
# 将 ls 的数据存一份到 ~/homefile ,同时屏幕也有输出讯息!

[dmtsai@study ~]$ ls -l / | tee -a ~/homefile | more
# 要注意! tee 后接的文件会被覆盖,若加上 -a 这个选项则能将讯息累加。

字符转换命令 tr, col, join, paste, expand

tr

tr 可以用来删除一段讯息当中的文字,或者是进行文字讯息的替换!

1
2
3
4
5
6
7
8
9
10
11
[dmtsai@study ~]$ tr [-ds] SET1 ...
选项与参数:
-d :删除讯息当中的 SET1 这个字串;
-s :取代掉重复的字符!

#将 last 输出的讯息中,所有的小写变成大写字符:
[dmtsai@study ~]$ last | tr '[a-z]' '[A-Z]'
# 不加单引号也是可以执行的,如:“ last | tr [a-z] [A-Z] ”

#将 /etc/passwd 输出的讯息中,将冒号 (:) 删除
[dmtsai@study ~]$ cat /etc/passwd | tr -d ':'

col

用来简单的处理将 [tab] 按键取代成为空白键.(***还有其它用途???***)

1
2
3
4
5
6
7
[dmtsai@study ~]$ col [-xb]
选项与参数:
-x :将 tab 键转换成对等的空白键

#利用 cat -A 显示出所有特殊按键,最后以 col 将 [tab] 转成空白
[dmtsai@study ~]$ cat -A /etc/man_db.conf <==此时会看到很多 ^I 的符号,那就是 tab
[dmtsai@study ~]$ cat /etc/man_db.conf | col -x | cat -A | more

分区命令 split

如果有文件太大,导致一些携带式设备无法复制的问题,split 可以将一个大文件,依据文件大小或行数来分区,就可以将大文件分区成为小文件了

1
2
3
4
5
[dmtsai@study ~]$ split [-bl] file PREFIX
选项与参数:
-b :后面可接欲分区成的文件大小,可加单位,例如 b, k, m 等;
-l :以行数来进行分区。
PREFIX :代表前置字符的意思,可作为分区文件的前导文字。

范例一:我的 /etc/services 有六百多K,若想要分成 300K 一个文件时?

1
2
3
4
5
6
[dmtsai@study ~]$ cd /tmp; split -b 300k /etc/services services
[dmtsai@study tmp]$ ll -k services*
-rw-rw-r--. 1 dmtsai dmtsai 307200 Jul 9 22:52 servicesaa
-rw-rw-r--. 1 dmtsai dmtsai 307200 Jul 9 22:52 servicesab
-rw-rw-r--. 1 dmtsai dmtsai 55893 Jul 9 22:52 servicesac
# 那个文件名可以随意取的啦!我们只要写上前导文字,小文件就会以xxxaa, xxxab, xxxac 等方式来创建小文件的!

“范例二:如何将上面的三个小文件合成一个文件,文件名为 servicesback

1
2
#用数据流重导向合成文件
[dmtsai@study tmp]$ cat services* >> servicesback

范例三:使用 ls -al / 输出的信息中,每十行记录成一个文件

1
2
3
4
5
6
7
[dmtsai@study tmp]$ ls -al / | split -l 10 - lsroot
[dmtsai@study tmp]$ wc -l lsroot*
10 lsrootaa
10 lsrootab
4 lsrootac
24 total
# 重点在那个 - 啦!一般来说,如果需要 stdout/stdin 时,但偏偏又没有文件,有的只是 - 时,那么那个 - 就会被当成 stdin 或 stdout ~

参数代换 xargs(后面貌似不能用alias)

1
2
3
4
5
6
7
8
[dmtsai@study ~]$ xargs [-0epn] command
选项与参数:
-0 :如果输入的 stdin 含有特殊字符,例如 `, \, 空白键等等字符时,这个 -0 参数
可以将他还原成一般字符。这个参数可以用于特殊状态!
-e :这个是 EOF (end of file) 的意思。后面可以接一个字符串,当 xargs 分析到这个字串时,就会停止继续工作!
-p :在执行每个指令的 argument 时,都会询问使用者的意思;
-n :后面接次数,每次 command 指令执行时,要使用几个参数的意思。
当 xargs 后面没有接任何的指令时,默认是以 echo 来进行输出喔!

范例一:将 /etc/passwd 内的第一栏取出,仅取三行,使用 id 这个指令将每个帐号内容秀出来.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[dmtsai@study ~]$ id root
uid=0(root) gid=0(root) groups=0(root)
# 这个 id 指令可以查询使用者的 UID/GID 等信息

[dmtsai@study ~]$ id $(cut -d ':' -f 1 /etc/passwd | head -n 3)
# 虽然使用 $(cmd) 可以预先取得参数,但可惜的是, id 这个指令“仅”能接受一个参数而已!
# 所以上述的这个指令执行会出现错误!根本不会显示用户的 ID 啊!

[dmtsai@study ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | id
uid=1000 (dmtsai) gid=1000 (dmtsai) groups=1000 (dmtsai),10(wheel)
# 因为 id 并不是管线命令,因此在上面这个指令执行后,前面的东西通通不见!只会执行 id!

[dmtsai@study ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs id
# 依旧会出现错误!这是因为 xargs 一口气将全部的数据通通丢给 id 处理~但id 就接受 1 个参数!

[dmtsai@study ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -n 1 id
uid=0(root) gid=0(root) groups=0(root)
uid=1(bin) gid=1(bin) groups=1(bin)
uid=2(daemon) gid=2(daemon) groups=2(daemon)
# 通过 -n 来处理,一次给予一个参数,因此上述的结果就 OK 正常的显示啰!

范例二:同上,但是每次执行 id 时,都要询问使用者是否动作?

1
2
3
4
5
6
[dmtsai@study ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -p -n 1 id
id root ?...y
uid=0(root) gid=0(root) groups=0(root)
id bin ?...y
.....(下面省略).....
# 呵呵!这个 -p 的选项可以让使用者的使用过程中,被询问到每个指令是否执行!

范例三:将所有的 /etc/passwd 内的帐号都以 id 查阅,但查到 sync 就结束指令串

1
2
3
4
[dmtsai@study ~]$ cut -d ':' -f 1 /etc/passwd | xargs -e'sync' -n 1 id
# 仔细与上面的案例做比较。也同时注意,那个 -e'sync' 是连在一起的,中间没有空白键。
# 上个例子当中,第六个参数是 sync 啊,那么我们下达 -e'sync' 后,则分析到 sync 这个字串时,
# 后面的其他 stdin 的内容就会被 xargs 舍弃掉了!

很多指令其实并不支持管线命令,因此我们可以通过 xargs 来提供该指令引用 standard input 之用!

范例四:找出 /usr/sbin 下面具有特殊权限的文件名,并使用 ls -l 列出详细属性

1
2
3
4
5
6
[dmtsai@study ~]$ find /usr/sbin -perm /7000 | xargs ls -l
-rwx--s--x. 1 root lock 11208 Jun 10 2014 /usr/sbin/lockdev
-rwsr-xr-x. 1 root root 113400 Mar 6 12:17 /usr/sbin/mount.nfs
-rwxr-sr-x. 1 root root 11208 Mar 6 11:05 /usr/sbin/netreport
.....(下面省略).....
# 也可以使用“ ls -l $(find /usr/sbin -perm /7000) ”来处理这个范例!

减号 " - " 的用途

管线命令当中,常常会使用到前一个指令的 stdout 作为这次的 stdin , 某些指令需要用到文件名称 (例如 tar) 来进行处理时,该 stdin 与 stdout 可以利用减号 “-” 来替代.

1
2
[root@study ~]# mkdir /tmp/homeback
[root@study ~]# tar -cvf - /home | tar -xvf - -C /tmp/homeback

上面这个例子是:“将 /home 里面的文件给他打包,但打包的数据不是纪录到文件,而是传送到 stdout; 经过管线后,将 tar -cvf - /home 传送给后面的 tar -xvf - ”。后面的这个 - 则是取用前一个指令的 stdout, 因此,我们就不需要使用 filename 了