Haste makes waste

linux-vbird-10-使用bash

Posted on By lijun

0. 总结

  • 由于核心在内存中是受保护的区块,因此我们必须要通过“ Shell ”将我们输入的指令与 Kernel 沟通,好让 Kernel 可以控制硬件来正确无误的工作

  • 学习 shell 的原因主要有:命令行的 shell 在各大 distribution 都一样;远端管理时命令行 速度较快; shell 是管理 Linux 系统非常重要的一环,因为 Linux 内很多控制都是以 shell 撰写的。

  • 系统合法的 shell 均写在 /etc/shells 文件中;

  • 使用者默认登陆取得的 shell 记录于 /etc/passwd 的最后一个字段;

  • bash 的功能主要有:命令编修能力;命令与文件补全功能;命令别名设置功能;工作控 制、前景背景控制;程序化脚本;万用字符

  • type 可以用来找到执行指令为何种类型,亦可用于与 which 相同的功能;

  • 变量就是以一组文字或符号等,来取代一些设置或者是一串保留的数据

  • 变量主要有环境变量与自订变量,或称为全域变量与区域变量

  • 使用envexport可观察环境变量,其中 export 可以将自订变量转成环境变量;

  • set可以观察目前 bash 环境下的所有变量;

  • $?亦为变量,是前一个指令执行完毕后的回传值。在 Linux 回传值为 0 代表执行成功;

  • locale 可用于观察语系数据;

  • 可用read让使用者由键盘输入变量的值

  • ulimit可用以限制使用者使用系统的资源情况 bash 的配置文件主要分为 login shell 与 non-login shell。login shell 主要读取 /etc/profile 与 ~/.bash_profile, non-login shell 则仅读取 ~/.bashrc

  • 在使用 vim 时,若不小心按了 [crtl]+s 则画面会被冻结。你可以使用 [ctrl]+q 来解除冻结

  • 万用字符主要有: *, ?, [] 等等

  • 数据流重导向通过 >, 2>, < 之类的符号将输出的信息转到其他文件或设备去;

  • 连续命令的下达可通过 ; && || 等符号来处理

  • 管线命令的重点是:“管线命令仅会处理 standard output,对于 standard error output 会予以忽略”

-“管线命令必须要能够接受来自前一个指令的数据成为 standard input 继续处理 才行。”

  • 本章介绍的管线命令主要有:cut, grep, sort, wc, uniq, tee, tr, col, join, paste, expand, split, xargs 等。

1. 认识BASH

狭义的壳程序指的是命令行方面的软件,包括本章要介绍的bash等,基于命令行的shell不好学,有很多命令行要记,但是学好了shell好处多多:

  1. linux有不同的发行版本,不同的发行版本其图形接口可能不同,但是其命令行的shell是一样的。

  2. 更方便的远程管理,命令行比较快。

  3. shell能将日常的工作作成script,达到作业自动化。

由于各种历史原因,存在多个不同的shell,如下以centos为例:

  • /bin/sh (已经被 /bin/bash 所取代)
  • /bin/bash (就是 Linux 默认的 shell)
  • /bin/tcsh (整合 C Shell ,提供更多的功能)
  • /bin/csh (已经被 /bin/tcsh 所取代)

其中bash是linux发行版中的标准shell,bash主要的优点如下:

  1. 命令记录能力(history),历史命令保存在 ~/.bash_history
  2. 命令名与文件名的补全功能(tab)
  3. 命令别名设置功能(alias),比如某个常用命令比较长的话,可以alias lm='ls -al' ,用lm来取代
  4. 程序化脚本化(shell scripts)
  5. 通配符(wildcard),想知道 /usr/bin 下面有多少以 X 为开头的文件吗?使用:ls -l /usr/bin/X*就能够知道

1.1. 查询指令是否为 Bash shell 的内置命令: type

通过 type 这个指令我们可以知道每个指令是否为 bash 的内置指令。 此外,由于利用 type 搜 寻后面的名称时,如果后面接的名称并不能以可执行文件的状态被找到, 那么该名称是不会 被显示出来的。也就是说, type 主要在找出“可执行文件”而不是一般文件文件名喔! 呵呵! 所以,这个 type 也可以用来作为类似 which 指令的用途啦!找指令用的!

[root@CMDBServerDev04 ~]# type ls
ls  `ls --color=auto' のエイリアスです
[root@CMDBServerDev04 ~]# type cd
cd はシェル組み込み関数です

# 使用tab列举出所有ls开头的命令

[root@CMDBServerDev04 ~]# type ls
ls           lsb_release  lscpu        lslocks      lsmod        lspci
lsattr       lsblk        lsinitrd     lslogins     lsof         lsscsi

1.2. 指令的下达与快速编辑按钮

  • 如果一串命令很长,无法在一行内输入,可以使用 \进行跳转,紧接后面的按下的enter就没有执行功能,能在后面继续输入命令
[root@CMDBServerDev04 lijuntest]# cp 1.txt 2.txt 3.txt 4.txt 5.txt 6.txt 7.txt \
> 8.txt 9.txt myfolder
[root@CMDBServerDev04 lijuntest]# cd myfolder/
[root@CMDBServerDev04 myfolder]# ls
1.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt  9.txt
  • 快速编辑命令
组合键 功能 组合键 功能
[ctrl]+u 从光标处向前删除指令串 [ctrl]+k 向后删除指令串
[ctrl]+a 将光标移动到指令串最前面 [ctrl]+e 移动到指令串最后面

2. Shell的变量功能

2.1 影响 bash 环境操作的变量

例如你下达 ls 这个指令时,系统就是通过 PATH 这个变量里面的内容所记录的路径顺序来搜寻指令的! 如果在搜寻完 PATH 变量内的路径还找不到 ls 这个指令时, 就会在屏幕上显示“ command not found ”。 为了区分与自订变量的不同,环境变量通常都用大写字母表示,常见的环境变量如下:


[root@CMDBServerDev04 ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

[root@CMDBServerDev04 ~]# echo $HOME
/root

[root@CMDBServerDev04 ~]# echo $MAIL
/var/spool/mail/root

[root@CMDBServerDev04 ~]# echo $SHELL
/bin/bash

2.2 变量的取用与设置: echo,变量设置规则,unset

  • 变量的设置与打印
# 当前没有设置该变量,故为空
[root@CMDBServerDev04 ~]# echo ${myname}

# 变量设置
[root@CMDBServerDev04 ~]# myname="lijun"
[root@CMDBServerDev04 ~]# echo ${myname}
lijun

# 打印上面设置的变量
[root@CMDBServerDev04 ~]# echo $myname
lijun
  • 双引号与单引号

单引号内部的字符直接输出,双引号内部如果有$,可以输出其变量

[root@CMDBServerDev04 ~]# var="lang is $LANG"
[root@CMDBServerDev04 ~]# echo $var
lang is ja_JP.UTF-8
[root@CMDBServerDev04 ~]# var='lang is $LANG'
[root@CMDBServerDev04 ~]# echo $var
lang is $LANG
  • 在一串指令的执行中,还需要借由其他额外的指令所提供的信息时,可以使用反单引号```,如:
[root@CMDBServerDev04 ~]# myhost=hostname
[root@CMDBServerDev04 ~]# echo $myhost
hostname

# 下面的命令,与上面的等效
[root@CMDBServerDev04 ~]# echo `hostname`
CMDBServerDev04

# 示例2,进入对应的kernel
[root@CMDBServerDev04 ~]# cd /lib/modules/`uname -r`/kernel
[root@CMDBServerDev04 kernel]# cd ~
[root@CMDBServerDev04 ~]# cd /lib/modules/$(uname -r)/kernel
[root@CMDBServerDev04 kernel]# cd ~


[root@CMDBServerDev04 ~]# version=`uname -r`
[root@CMDBServerDev04 ~]# echo $version
3.10.0-327.el7.x86_64

  • 变量的扩增
[root@CMDBServerDev04 ~]# comman_phrase="JP"

# 后续接需要连接的字符串
[root@CMDBServerDev04 ~]# my_phrase=$comman_phrase"_amazon"
[root@CMDBServerDev04 ~]# echo $my_phrase
JP_amazon

# 示例2
[root@CMDBServerDev04 ~]# name="li-"
[root@CMDBServerDev04 ~]# myname=${name}"utasuke"
[root@CMDBServerDev04 ~]# echo $myname
li-utasuke

  • 取消变量使用unset,如:
[root@CMDBServerDev04 ~]# myname="lijun"
[root@CMDBServerDev04 ~]# echo $myname
lijun
[root@CMDBServerDev04 ~]# unset myname
[root@CMDBServerDev04 ~]# echo $myname
  • 使用export进行变量导出,使得可以在子程序中使用
[root@CMDBServerDev04 ~]# name="li-"

# 进入子程序
[root@CMDBServerDev04 ~]# bash

# 没有设置export,故在子程序中无法输出name
[root@CMDBServerDev04 ~]# echo $name

# 退出子程序
[root@CMDBServerDev04 ~]# exit
exit

# 导出变量name
[root@CMDBServerDev04 ~]# export name

# 再次进入子程序
[root@CMDBServerDev04 ~]# bash

# 可以输出变量name
[root@CMDBServerDev04 ~]# echo $name
li-
[root@CMDBServerDev04 ~]# exit
exit

2.3 环境变量的功能

[root@CMDBServerDev04 lijuntest]# env
...
MAIL=/var/spool/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
PWD=/root/lijuntest
LANG=ja_JP.UTF-8
HOME=/root
...


[root@CMDBServerDev04 lijuntest]# cd $HOME
[root@CMDBServerDev04 ~]#

# 通过export也可以得到类似的结果
[root@CMDBServerDev04 ~]# export
...
declare -x HOME="/root"
declare -x HOSTNAME="CMDBServerDev04"
...

2.4 变量键盘读取read,阵列array,宣告declare

  • 键盘读取
# 接收输入,将输入存储到myread变量
[root@CMDBServerDev04 ~]# read myread
hello,world!
# 打印出myread变量
[root@CMDBServerDev04 ~]# echo $myread
hello,world!

# 提示接收输入,并设置最长时间为30秒
[root@CMDBServerDev04 ~]# read -p "Please enter your name:" -t 30 myname
Please enter your name:lijun

# 打印出myname变量
[root@CMDBServerDev04 ~]# echo ${myname}
lijun
  • 宣告变量类型 declare / typeset

# 默认是字符串类型
[root@CMDBServerDev04 ~]# sum=100+200+300
[root@CMDBServerDev04 ~]# echo $sum
100+200+300

# 显式指定为整型
[root@CMDBServerDev04 ~]# declare -i sum=100+200+300
[root@CMDBServerDev04 ~]# echo $sum
600
# 将sum设置为环境变量
[root@CMDBServerDev04 ~]# declare -x sum
# 输出环境变量sum
[root@CMDBServerDev04 ~]# export | grep sum
declare -ix sum="600"

# 将sum设置为只读
[root@CMDBServerDev04 ~]# declare -r sum
# 试图修改sum会出错
[root@CMDBServerDev04 ~]# sum="wanttochange"
-bash: sum: readonly variable

# 将sum设置为非环境变量的自订变量
[root@CMDBServerDev04 ~]# declare +x sum

# 环境变量中找不到sum了
[root@CMDBServerDev04 ~]# export | grep sum
[root@CMDBServerDev04 ~]# declare -p sum
declare -ir sum="600"
  • 阵列array变量类型
[root@CMDBServerDev04 ~]# var[0]=0
[root@CMDBServerDev04 ~]# var[1]=1
[root@CMDBServerDev04 ~]# var[2]=2
[root@CMDBServerDev04 ~]# echo "${var[0]},${var[1]},${var[2]}"
0,1,2

2.5 ulimit 文件系统与程序的限制

# 列出当前用户的资源限制列表,0表示没有限制
[root@CMDBServerDev04 ~]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
...


# 限制用户只能创建10M以下的文件
[root@CMDBServerDev04 ~]# ulimit -f 10240

# 再次列出当前用户的资源限制列表
[root@CMDBServerDev04 ~]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) 10240
...

# 创建文件,最后显示超出大小限制
[root@CMDBServerDev04 ~]# dd if=/dev/zero of=123 bs=1M count=20
File size limit exceeded

# 下面是创建的文件,这里是byte为单位,实际是10240KB
[root@CMDBServerDev04 ~]# ls -al | grep 123
-rw-r--r--   1 root root  10485760 Feb  9 12:43 123

如果要复原ulimit的size,重新登录系统即可。

3. 命令别名与历史命令

3.1 命令别名设置 alias unalias


# 为了防止误删除,将删除默认带上确认提示
[root@CMDBServerDev04 ~]# alias rm="rm -i"
[root@CMDBServerDev04 ~]# rm 123
rm: remove regular file 123’? n

# 取消rm的重命名
[root@CMDBServerDev04 ~]# unalias rm
[root@CMDBServerDev04 ~]# rm 123

# 有时命令过长,用一个别名更加方便
[root@CMDBServerDev04 ~]# alias lm="ls -al | more"
[root@CMDBServerDev04 ~]# lm
...
-rw-r--r--   1 root root   9368661 Dec  7 11:26 apache-tomcat-8.0.47.tar.gz
...

# 打印当前的所有别名
[root@CMDBServerDev04 ~]# alias
...
alias lm='ls -al | more'
alias mv='mv -i'
...

3.2 历史命令

[root@CMDBServerDev04 ~]# alias h=history
[root@CMDBServerDev04 ~]# h
...
  657  dd if=/dev/zero of=123 bs=1M count=20
  658  ls
  659  ls -al
...

# 执行第658条command
[root@CMDBServerDev04 ~]# !658
ls
apache-tomcat-8.0.47.tar.gz 

# 执行上一次的命令
[root@CMDBServerDev04 ~]# !!
ls
apache-tomcat-8.0.47.tar.gz


# 执行以cl开头的命令,在上面是clear
[root@CMDBServerDev04 ~]# !cl
clear

使用history -c;history -w能更新history文件。

4. Bash shell的操作环境

4.1 路径与指令搜寻顺序

当一个命令比如ls被下达后,其运行的顺序是这样的:

  1. 由alias找到该指令来执行
  2. 由bash内置的builtin指令来执行
  3. 通过$PATH这个变量的顺序来搜寻到的第一个指令来执行
# 执行结果有颜色
[root@CMDBServerDev04 ~]# ls
apache-tomcat-8.0.47.tar.gz  cmdbuild-2.5.0 

# 执行结果无颜色
[root@CMDBServerDev04 ~]# /bin/ls
apache-tomcat-8.0.47.tar.gz  cmdbuild-2.5.0 

# 执行顺序如下,先执行的alias别名,故有color
[root@CMDBServerDev04 ~]# type -a ls
ls is aliased to `ls --color=auto'
ls is /usr/bin/ls

# 查看ls命令的别名内容
[root@CMDBServerDev04 ~]# alias | grep ls
alias ls='ls --color=auto'

# 比如给echo赋予别名
[root@CMDBServerDev04 ~]# alias echo="echo -n"

# 通过type可以查看echo命令的执行顺序
# 先别人alias,在builtin内置,最后用$PATH变量搜寻
[root@CMDBServerDev04 ~]# type -a echo
echo is aliased to `echo -n'
echo is a shell builtin
echo is /usr/bin/echo

4.2 进入OS时的欢迎消息

通过vi /etc/issuevi /etc/motd 可以编辑欢迎消息样式和内容

4.3 bash 的环境配置文件

记忆内容较多,暂时跳过

4.4 常用快捷key与掩码

  • 常用快捷key
命令 功能 命令 功能
Ctrl + C 终止目前的命令 Ctrl + D 输入结束 (EOF),例如邮件结束的时候;
Ctrl + M 就是 Enter Ctrl + S 暂停屏幕的输出
Ctrl + Q 恢复屏幕的输出 Ctrl + U 在提示字符下,将整列命令删除
Ctrl + Z “暂停”目前的命令    
  • 常用掩码
命令 功能
* 0个或多个任意字符
? 一定有一个任意字符
[ ] [abcd]指abcd四个中的一个字符
[ -] [1-9]指1到9的字符
[^ ] [^abc] 有非abc的字符
   
   
  • 特殊符号
命令 功能
# 注释
\ 将特殊字符或掩码还原成普通字符
| 管线命令
; 连续指令下达分隔符号:连续性命令的界定 (注意!与管线命令并不相同)
~ 使用者的主文件夹
$ 取用变量前置字符:亦即是变量之前需要加的变量取代值
& 工作控制 (job control):将指令变成背景下工作
! 逻辑运算意义上的“非” not 的意思!
/ 目录符号:路径分隔的符号
>, » 数据流重导向:输出导向,分别是“取代”与“累加”
<, « 数据流重导向:输入导向 (这两个留待下节介绍)
’ ‘ 单引号,不具有变量置换的功能 ($ 变为纯文本)
” “ 具有变量置换的功能! ($ 可保留相关功能)
` 两个“ ` ”中间为可以先执行的指令,亦可使用 $( )
( ) 在中间为子 shell 的起始与结束
{ } 在中间为命令区块的组合!

5. 数据流重导向

数据流重导向就是将某个指令执行后应该要出现在屏幕上的数据, 给他传输到 其他的地方,例如文件或者是设备(例如打印机之类)

# 输出到屏幕
[root@CMDBServerDev04 ~]# ls
apache-tomcat-8.0.47.tar.gz 

# 以追加的方式输出到文件
[root@CMDBServerDev04 ~]# ls >> ls.txt

# 以追加的方式,将error信息输出到文件
[root@CMDBServerDev04 ~]# declare -i div=2/0 2>>error.txt

注意: >是以覆盖的方式输出,>>以追加的方式输出。

  • /dev/null 垃圾桶黑洞设备
# 将错误的数据丢弃,屏幕上显示正确的数据
[root@CMDBServerDev04 ~]# find /home -name .bashrc 2>> /dev/null
/home/kotani/.bashrc
  • <<< 标准输入
# 接收输入,写入到文件
[root@CMDBServerDev04 ~]# cat > input1.txt
hello,here is my first msg

# 覆盖的方式输入
[root@CMDBServerDev04 ~]# cat > input1.txt
12345

# 追加的方式输入
[root@CMDBServerDev04 ~]# cat >> input1.txt
789

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

  • ; 依次执行多条命令
[root@CMDBServerDev04 lijuntest]# ls;mkdir newfolder;ls
1.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt  9.txt
1.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt  9.txt  newfolder
  • &&||,按照指定逻辑进行多条命令的执行
命令 功能
cmd1 && cmd2 若 cmd1 执行完毕且正确执行($?=0),则开始执行 cmd2。 2. 若 cmd1 执行完毕且为错误 ($?≠0),则 cmd2 不执行。
cmd1 || cmd2 若 cmd1 执行完毕且正确执行($?=0),则 cmd2 不执行。 2. 若 cmd1 执 行完毕且为错误 ($?≠0),则开始执行 cmd2。
# 先创建一个文件夹,在ls该文件夹,如果存在,则在下面创建文件
[root@CMDBServerDev04 lijuntest]# mkdir newfolder;ls newfolder && touch newfolder/newfile

# 先ls newfolder2,因为这个文件夹不存在,故后续也无法执行
[root@CMDBServerDev04 newfolder]# ls newfolder2 && touch newfolder2/newfile
ls: cannot access newfolder2: No such file or directory

# 先ls newfolder2,如果不成功,则新建该文件夹,新建成功后在该文件夹下touch一个新文件
[root@CMDBServerDev04 newfolder]# ls newfolder2 || mkdir newfolder2 && touch newfolder2/newfile

6. 管线命令

  • 管线命令仅会处理 standard output,对于 standard error output 会予以忽略
  • 管线命令必须要能够接受来自前一个指令的数据成为 standard input 继续处理才行。

如 less,more,head,tail都是管线命令。

[root@CMDBServerDev04 ~]# ls -al | less
[root@CMDBServerDev04 ~]# ls -al | head

如果硬要让 standard error 可以被管线命令所使用,那该如何处理?其实就 是通过上一小节的数据流重导向即可! 让 2>&1 加入指令中~就可以让 2> 变成 1> 了。

6.1 截取命令 cut grep

待续

6.2 排序命令 sort wc uniq

待续

6.3 双向重导向 tee

待续

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

待续

6.5 分区命令 split

待续

6.6 参数代换 xargs

待续

6.7 减号-的用途

待续