第十一章 认识与学习BASH【鸟哥linux私房菜学习笔记】

认识与学习BASH

一、认识bash这个shell

(一)bash shell 的功能

1、history指令

默认的命令记忆功能为1000条命令。本次登录过程中使用的命令保存在内存中,之前登录的命令保存在“~/bash_history”。可以通过上下箭头来查找历史功能

问题:当电脑被入侵,黑客可以查询曾经的操作,而记录中有对系统的操作(比如输入过MySQL的密码),那么还是很危险的。所以记录的历史命令操作有多少,就是见仁见智了。

2、tab命令补全

tab接在一串命令的第一个不完整单词的后面,则是补全命令

tab接在一串命令的第二个不完整的单词后面,是补全文件名

举例:某文件夹下只有一个以test开头的文件:test123,那么输入“more tes”再按tab,可以补全;

但是如果某个文件夹有,有文件test1,test2,那么输入“more test”后,无反应。

“** tab tab”是列出所有以**开头的指令操作,仅对于指令,不针对文件

3、别名配置

alias [ˈeɪliəs]:别名

直接输入alias可以查看当前使用别名情况

或者可以通过alias进行别名设置:


以后想查看进程信息,输入“lm”即可

4、通配符

当想要查询某个文件夹下以X开头的文件有哪些时,使用:ls -l /usr/bin/X* 

注意文件结构,否则容易找不到被提示没有该目录。

(二)bash shell的内建命令:type

通过type这个命令,我们可以知道哪些是内置命令,哪些是后来外部添加上的。内置命令一般保存在root下的bin目录下,而外部命令需要输入命令“type  -p  外部命令name ”。(注意:-p 如果后面接的name为外部命令时,才会显示完整文件名)


type对于大工程管理意义重大,比如给多个电脑搭建同样的平台,如果配置的员工不熟悉老电脑,就要靠这个命令来找可执行文件的位置,保证配置统一。

二、Shell变量

(一)变量的取用与配置:echo, 变量配置守则, unset

1、变量的配置守则

    1)等号两边不能直接出现空格符,如果在等号右边赋值时需要使用空格,则要加单引号或者双引号 。

myname=VBird Tsai是错误的;需要加上单引号或者双引号。


等号右边有空格的时候,必须要加单引号或者双引号,如果没有空格,即使有特殊字符,也可以直接赋值,且会显示变量内容,如上图。(目前接触到的,“特殊字符”是指“$”,但是跳脱字符“\”,在单引号和双引号中,都能保持活性,举例如图

    2)双引号内的特殊字符,可以保持原来的特性;单引号内,全部视为纯文本

    第二行的错误,是因为没有加“$”符号,所以打印出了变量名

    3)跳脱字符“\”

    可以使比如“\”“enter”这种具有特殊含义的符号,转化为正常符号

    4)在命令中引用变量,可以使用$符号或者单引号

    扩展:带变量的数学运算

范例六:如何进入到您目前核心的模块目录?
[root@www ~]# cd /lib/modules/`uname -r`/kernel
        上面的范例其实执行了两步,第一步是进行反单引号的内容,得到内核版本为2.6.18-128.el5,第二步试讲上述的结果带入到原命令。

    5)扩增内容时,也可用$

     path="$PATH":/home/bin

    6)通常大写字符为系统默认变量,自行设置的变量使用小写字符,方便判断

    7)取消变量

       

    8)如果其他程序中需要使用变量,则要把变量变为环境变量

    export val_name

范例一:配置一变量 name ,且内容为 VBird
[root@www ~]# 12name=VBird
-bash: 12name=VBird: command not found  <==屏幕会显示错误!因为不能以数字开头!
[root@www ~]# name = VBird            <==还是错误!因为有空白!
[root@www ~]# name=VBird              <==OK 的啦!

范例二:承上题,若变量内容为 VBird's name 呢,就是变量内容含有特殊符号时:
[root@www ~]# name=VBird's name  
# 单引号与双引号必须要成对,在上面的配置中仅有一个单引号,因此当你按下 enter 后,
# 你还可以继续输入变量内容。这与我们所需要的功能不同,失败啦!
# 记得,失败后要复原请按下 [ctrl]-c 结束!
[root@www ~]# name="VBird's name"    <==OK 的啦!
# 命令是由左边向右找→,先遇到的引号先有用,因此如上所示,单引号会失效!
[root@www ~]# name='VBird's name'    <==失败的啦!
# 因为前两个单引号已成对,后面就多了一个不成对的单引号了!因此也就失败了!
[root@www ~]# name=VBird\'s\ name     <==OK 的啦!
# 利用反斜杠 (\) 跳脱特殊字符,例如单引号与空格键,这也是 OK 的啦!

范例三:我要在 PATH 这个变量当中『累加』:/home/dmtsai/bin 这个目录
[root@www ~]# PATH=$PATH:/home/dmtsai/bin
[root@www ~]# PATH="$PATH":/home/dmtsai/bin
[root@www ~]# PATH=${PATH}:/home/dmtsai/bin
# 上面这三种格式在 PATH 里头的配置都是 OK 的!但是底下的例子就不见得啰!

范例四:承范例三,我要将 name 的内容多出 "yes" 呢?
[root@www ~]# name=$nameyes  
# 知道了吧?如果没有双引号,那么变量成了啥?name 的内容是 $nameyes 这个变量!
# 呵呵!我们可没有配置过 nameyes 这个变量吶!所以,应该是底下这样才对!
[root@www ~]# name="$name"yes
[root@www ~]# name=${name}yes  <==以此例较佳!

范例五:如何让我刚刚配置的 name=VBird 可以用在下个 shell 的程序?
[root@www ~]# name=VBird
[root@www ~]# bash        <==进入到所谓的子程序
[root@www ~]# echo $name  <==子程序:再次的 echo 一下;
       <==嘿嘿!并没有刚刚配置的内容喔!
[root@www ~]# exit        <==子程序:离开这个子程序
[root@www ~]# export name
[root@www ~]# bash        <==进入到所谓的子程序
[root@www ~]# echo $name  <==子程序:在此运行!
VBird  <==看吧!出现配置值了!
[root@www ~]# exit        <==子程序:离开这个子程序

范例一:配置一变量 name ,且内容为 VBird
[root@www ~]# 12name=VBird
-bash: 12name=VBird: command not found  <==屏幕会显示错误!因为不能以数字开头!
[root@www ~]# name = VBird            <==还是错误!因为有空白!
[root@www ~]# name=VBird              <==OK 的啦!

范例二:承上题,若变量内容为 VBird's name 呢,就是变量内容含有特殊符号时:
[root@www ~]# name=VBird's name  
# 单引号与双引号必须要成对,在上面的配置中仅有一个单引号,因此当你按下 enter 后,
# 你还可以继续输入变量内容。这与我们所需要的功能不同,失败啦!
# 记得,失败后要复原请按下 [ctrl]-c 结束!
[root@www ~]# name="VBird's name"    <==OK 的啦!
# 命令是由左边向右找→,先遇到的引号先有用,因此如上所示,单引号会失效!
[root@www ~]# name='VBird's name'    <==失败的啦!
# 因为前两个单引号已成对,后面就多了一个不成对的单引号了!因此也就失败了!
[root@www ~]# name=VBird\'s\ name     <==OK 的啦!
# 利用反斜杠 (\) 跳脱特殊字符,例如单引号与空格键,这也是 OK 的啦!

范例三:我要在 PATH 这个变量当中『累加』:/home/dmtsai/bin 这个目录
[root@www ~]# PATH=$PATH:/home/dmtsai/bin
[root@www ~]# PATH="$PATH":/home/dmtsai/bin
[root@www ~]# PATH=${PATH}:/home/dmtsai/bin
# 上面这三种格式在 PATH 里头的配置都是 OK 的!但是底下的例子就不见得啰!

范例四:承范例三,我要将 name 的内容多出 "yes" 呢?
[root@www ~]# name=$nameyes  
# 知道了吧?如果没有双引号,那么变量成了啥?name 的内容是 $nameyes 这个变量!
# 呵呵!我们可没有配置过 nameyes 这个变量吶!所以,应该是底下这样才对!
[root@www ~]# name="$name"yes
[root@www ~]# name=${name}yes  <==以此例较佳!

范例五:如何让我刚刚配置的 name=VBird 可以用在下个 shell 的程序?
[root@www ~]# name=VBird
[root@www ~]# bash        <==进入到所谓的子程序
[root@www ~]# echo $name  <==子程序:再次的 echo 一下;
       <==嘿嘿!并没有刚刚配置的内容喔!
[root@www ~]# exit        <==子程序:离开这个子程序
[root@www ~]# export name
[root@www ~]# bash        <==进入到所谓的子程序
[root@www ~]# echo $name  <==子程序:在此运行!
VBird  <==看吧!出现配置值了!
[root@www ~]# exit        <==子程序:离开这个子程序

(二)环境变量的功能

    补充:

  •    Linux脚本开头#!/bin/bash和#!/bin/sh是什么意思

#!/bin/sh是指此脚本使用/bin/sh来解释执行,#!是特殊的表示符,其后面根的是此解释此脚本的shell的路径。

其实第一句的#!是对脚本的解释器程序路径,脚本的内容是由解释器解释的,我们可以用各种各样的解释器来写对应的脚本。

比如说/bin/csh脚本,/bin/perl脚本,/bin/awk脚本,/bin/sed脚本,甚至/bin/echo等等。

#!/bin/bash同理。

1、用env查看环境变量与常见环境变量说明

范例一:列出目前的shell环境下的所有环境变数与其内容。
[dmtsai@study ~]$ env 
HOSTNAME=study.centos.vbird     <==这部主机的主机名称 
TERM=xterm                      <==这个终端机使用的环境是什么类型 
SHELL=/bin/bash                 <==目前这个环境下,使用的Shell是哪一个程式?
HISTSIZE=1000                   <== 『记录指令的笔数』在CentOS预设可记录1000笔 
OLDPWD=/home/dmtsai             <==上一个工作目录的所在 
LC_ALL=en_US.utf8               <==由于语系的关系,鸟哥偷偷丢上来的一个设定 
USER=dmtsai                     <==使用者的名称啊!
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd= 40;33;01:
or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st= 37;44:ex=01;32:
*.tar=01...                     <==一些颜色显示 
MAIL=/var/spool/mail/dmtsai     <==这个使用者所取用的mailbox位置
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
PWD=/home/dmtsai                <==目前使用者所在的工作目录(利用pwd取出!) 
LANG=zh_TW.UTF-8                <==这个与语系有关,底下会再介绍!
HOME=/home/dmtsai               <==这个使用者的家目录啊!
LOGNAME=dmtsai                  <==登入者用来登入的帐号名称 
_=/usr/bin/env                  <==上一次使用的指令的最后一个参数(或指令本身)
PATH:就是运行文件搜寻的路径啦~目录与目录中间以冒号(:)分隔, 由于文件的搜寻是依序由 PATH 的变量内的目录来查询,所以,目录的顺序也是重要的喔。


2、用set查看所有变量(含环境变量与自定义变量)

[root@www ~]# set
BASH=/bin/bash           <== bash 的主程序放置路径
BASH_VERSINFO=([0]="3" [1]="2" [2]="25" [3]="1" [4]="release" 
[5]="i686-redhat-linux-gnu")      <== bash 的版本啊!
BASH_VERSION='3.2.25(1)-release'  <== 也是 bash 的版本啊!
COLORS=/etc/DIR_COLORS.xterm      <== 使用的颜色纪录文件
COLUMNS=115              <== 在目前的终端机环境下,使用的字段有几个字符长度
HISTFILE=/root/.bash_history      <== 历史命令记录的放置文件,隐藏档
HISTFILESIZE=1000        <== 存起来(与上个变量有关)的文件之命令的最大纪录笔数。
HISTSIZE=1000            <== 目前环境下,可记录的历史命令最大笔数。
HOSTTYPE=i686            <== 主机安装的软件主要类型。我们用的是 i686 兼容机器软件
IFS=$' \t\n'             <== 默认的分隔符
LINES=35                 <== 目前的终端机下的最大行数
MACHTYPE=i686-redhat-linux-gnu    <== 安装的机器类型
MAILCHECK=60             <== 与邮件有关。每 60 秒去扫瞄一次信箱有无新信!
OLDPWD=/home             <== 上个工作目录。我们可以用 cd - 来取用这个变量。
OSTYPE=linux-gnu         <== 操作系统的类型!
PPID=20025               <== 父程序的 PID (会在后续章节才介绍)
PS1='[\u@\h \W]\$ '      <== PS1 就厉害了。这个是命令提示字符,也就是我们常见的
                             [root@www ~]# 或 [dmtsai ~]$ 的配置值啦!可以更动的!
PS2='> '                 <== 如果你使用跳脱符号 (\) 第二行以后的提示字符也
name=VBird               <== 刚刚配置的自定义变量也可以被列出来喔!
$                        <== 目前这个 shell 所使用的 PID
?                        <== 刚刚运行完命令的回传值。

1)PS1:提示字符的配置

“命令提示符”信息,每次按下“enter”执行完命令之后,最后要再次出现提示符时,就会主动读取这个变量的信息。PS1内显示的是一些特殊符号,这些特殊符号可以显示不同的信息。

“\”反斜杠后面的内容仅仅是ps1的特殊功能,与bash无关。

例如:

那么假设我想要有类似底下的提示字符:[root@www /home/dmtsai 16:50 #12]#

那个 # 代表第 12 次下达的命令。那么应该如何配置 PS1 呢?

[dmtsai@study ~]$ cd /home
[dmtsai@study home]$ PS1='[\u@\h \w \A #\#]\$ '
[dmtsai@study /home 17:02 #85]$

这里用单引号双引号都可以。

2)$:目前这个线程的线程代号

3)?:关于上次执行命令的回传码

[root@www ~]# echo $SHELL
/bin/bash                                  <==可顺利显示!没有错误!
[root@www ~]# echo $?
0                                          <==因为没问题,所以回传值为 0
[root@www ~]# 12name=VBird
-bash: 12name=VBird: command not found     <==发生错误了!bash回报有问题
[root@www ~]# echo $?
127                                        <==因为有问题,回传错误代码(非为0)
# 错误代码回传值依据软件而有不同,我们可以利用这个代码来搜寻错误的原因喔!
[root@www ~]# echo $?
0
# 咦!怎么又变成正确了?这是因为 "?" 只与『上一个运行命令』有关,
# 所以,我们上一个命令是运行『 echo $? 』,当然没有错误,所以是 0 没错!

3、自变量变成环境变量

自变量与环境变量之间的差异在于是否可以被子程序所继续引用


常常在主文件中执行

export 变量名

环境变量=全局变量

自定义变量=局部变量

(三)影响显示结果的语系变量(locale)

(四)变量的有效范围

        为什么环境变量可以被子程序使用?学理是这样的

        当启用shell程序的时候,操作系统会自动开辟一段内存块给shell,其中存放的变量即为环境变量;

        可以通过export将自定义变量变成环境变量,存入上述内存块中;

        当启动子进程离开主进程时,子进程会将父进程的环境变量所在的内存块,写入到自己的环境变量所在的内存块中。

(五)变量键盘读取、数组与声明:read,array,declare

1、read

[root@www ~]# read [-pt] variable
选项与参数:
-p  :后面可以接提示字符!
-t  :后面可以接等待的『秒数!』这个比较有趣~不会一直等待使用者啦!

范例一:让用户由键盘输入一内容,将该内容变成名为 atest 的变量
[root@www ~]# read atest
This is a test        <==此时光标会等待你输入!请输入左侧文字看看
[root@www ~]# echo $atest
This is a test          <==你刚刚输入的数据已经变成一个变量内容!

范例二:提示使用者 30 秒内输入自己的大名,将该输入字符串作为名为 named 的变量内容
[root@www ~]# read -p "Please keyin your name: " -t 30 named
Please keyin your name: VBird Tsai   <==注意看,会有提示字符喔!
[root@www ~]# echo $named
VBird Tsai        <==输入的数据又变成一个变量的内容了!

  • read后面直接加变量名,那么下面会主动出现一个空白行等待输入,如范例一,-t代表要在多少秒之内输入内容,-p后面跟着的是文字提示,这样在输入光标前就会有文字提示,更交互友好。

(六)与文件系统及程序的限制关系:ulimit

限制用户的某些系统资源,比如CPU,内存等等。所以如果有一天无法创建文件的时候,可以看一下ulimit配置。如果想要复原ulimit的设置最简单的方法就是注销再登陆,否则需要以ulimit设置才行。但是一般用户设置-f只能减少文件大小,不能增加文件容量。

范例二:限制用户仅能创建 10MBytes 以下的容量的文件
[root@www ~]# ulimit -f 10240
[root@www ~]# ulimit -a
file size               (blocks, -f) 10240 <==最大量为10240Kbyes,相当10Mbytes
[root@www ~]# dd if=/dev/zero of=123 bs=1M count=20
File size limit exceeded <==尝试创建 20MB 的文件,结果失败了!

(七)变量内容的删除、替代与替换

1、变量内容的删除与替换


path,path1,path2变量的值是一样的。

${path#/*local}
   上面的特殊字体部分是关键词!用在这种删除模式所必须存在的

${path#/*local}
   这就是原本的变量名称,以上面范例二来说,这里就填写 path 这个『变量名称』啦!

${path#/*local}
   这是重点!代表『从变量内容的最前面开始向右删除』,且仅删除最短的那个
[root@bogon ~]$echo ${path2##/*local}   代表的是删除最长的数据
/bin:/usr/sbin:/usr/bin:/root/bin


仅保留最后的一个目录

综上:
#:符合替换文字的“最短的”那一个;
##:符合替换文字的“最长的”那一个。

范例六:将path的变数内容内的sbin取代成大写SBIN: 
[dmtsai@study ~]$ echo ${path/sbin/SBIN} 
/usr/local/bin:/usr/bin:/usr/local/ SBIN :/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
 #这个部分就容易理解的多了!关键字在于那两个斜线,两斜线中间的是旧字串
# 后面的是新字串,所以结果就会出现如上述的特殊字体部分啰!

[dmtsai@study ~]$ echo ${path//sbin/SBIN} 
/usr/local/bin:/usr/bin:/usr/local/ SBIN :/usr/ SBIN :/home/dmtsai/.local/bin :/home/dmtsai/bin
 #如果是两条斜线,那么就变成所有符合的内容都会被取代喔!
综上:
1.#代表从前往后删除,%代表从后往前删除【鸟哥没有提到%的总结】
2.#和%后面紧跟着就是删除范围,比如mail=/var/spool/mail/root,如果想只留下用户名root,那么输入${mail##/*/},意思是删除从跟第一个/开始一直到最后一个/之间的全部内容

3.%后面紧跟着是从最后开始删除到的字符,例如mail=/var/spool/mail/root,如果想只留下/var/,那么输入${mail%spool*}

4. ${变量名/旧字符串/新字符串}:第一个符合“旧字符串”的位置会被替换为“新字符串”

    ${变量名//旧字符串/新字符串}:两个斜杠,将会把变量中所有的“旧字符串”替换为“新字符串”

2、变量的测试与替换

直接看例子。

  • 使用“-”:旧变量永远保持不变:旧变量有内容时(空格或非空字符串),新变量等于旧变量,旧变量没有设置时,新变量等于替换内容。旧变量始终不变。
  • 使用“=”:旧变量无内容,新旧变量等于设置的值;旧变量有内容,新旧变量都不变。
  • 使用“?”:旧变量为空,报错,旧变量不为空,新变量等于旧变量。

案例如下:

范例一:测试一下是否存在username这个变数,若不存在则给予username内容为root 
[dmtsai@study ~]$ echo ${username} 
           <==由于出现空白,所以username可能不存在,也可能是空字串 
[dmtsai@study ~]$ username=${username-root} 
[dmtsai@study ~]$ echo ${username} 
root        <==因为username没有设定,所以主动给予名为root的内容。
[dmtsai@study ~]$ username="vbird tsai"  <==主动设定username的内容 
[dmtsai@study ~]$ username=${username-root} 
[dmtsai@study ~]$ echo ${username} 
vbird tsai <==因为username已经设定了,所以使用旧有的设定而不以root取代

sername 可能已经被设定为『空字串』了!果真如此的话,那你还可以使用底下的范例来给予 username 的内容成为root 喔!

范例二:若username未设定或为空字串,则将username内容设定为root 
[dmtsai@study ~]$ username="" 
[dmtsai@study ~]$ username=${username-root} 
[dmtsai@study ~]$ echo ${username} 
      <==因为username被设定为空字串了!所以当然还是保留为空字串!
[dmtsai@study ~]$ username=${username:-root} 
[dmtsai@study ~]$ echo ${username} 
root   <==加上『 : 』后若变数内容为空或者是未设定,都能够以后面的内容替换!

  • 使用“-”,旧变量永远保持不变:旧变量有内容时(空格或非空字符串),新变量等于旧变量,旧变量没有设置时,新变量等于替换内容。旧变量始终不变。
测试:若str不存在,测试一下var会变怎样?
[root@www ~]# unset str; var=${str-newvar}
[root@www ~]# echo var="$var", str="$str"
var=newvar, str=        <==因为 str 不存在,所以 var 为 newvar

测试:若 str 已存在,测试一下 var 会变怎样?:
[root@www ~]# str="oldvar"; var=${str-newvar}
[root@www ~]# echo var="$var", str="$str"
var=oldvar, str=oldvar  <==因为 str 存在,所以 var 等于 str 的内容

  • 使用“=”,旧变量无内容,新旧变量等于设置的值;旧变量有内容,新旧变量都不变。
测试:先假设 str 不存在 (用 unset) ,然后测试一下等号 (=) 的用法:
[root@www ~]# unset str; var=${str=newvar}
[root@www ~]# echo var="$var", str="$str"
var=newvar, str=newvar  <==因为 str 不存在,所以 var/str 均为 newvar

测试:如果 str 已存在了,测试一下 var 会变怎样?
[root@www ~]# str="oldvar"; var=${str=newvar}
[root@www ~]# echo var="$var", str="$str"
var=oldvar, str=oldvar  <==因为 str 存在,所以 var 等于 str 的内容
测试:若 str 不存在时,则 var 的测试结果直接显示 "无此变量"
[root@www ~]# unset str; var=${str?无此变量}
-bash: str: 无此变量    <==因为 str 不存在,所以输出错误信息 

测试:若 str 存在时,则 var 的内容会与 str 相同!
[root@www ~]# str="oldvar"; var=${str?novar}
[root@www ~]# echo var="$var", str="$str"
var=oldvar, str=oldvar  <==因为 str 存在,所以 var 等于 str 的内容

三、命令别名与历史命令

(一)历史命令:history

  • 可以查到所有的历史数据


  • !number:查看第number条命令
  • !!:查看上一条命令

四、Bash Shell 的操作环境

(一)命令运行顺序

我们已经知道系统里类似于ls的命令,不只有一个

那么当输入ls的时候,系统执行的是哪一个命令呢?规律如下:

a)以相对/绝对路径执行命令,例如“/bin/ls”或“./ls”;

b)alias重命名的命令

c)bash的内置命令(builtin)

d)通过$PATH这个变量的顺序找到的第一个命令

(二)bash的登录与欢迎信息

etc/issue:是本地登录时的欢迎信息

etc/issue.net: 是远程登录时使用当我们使用 telnet 连接到主机时,主机的登陆画面就会显示 /etc/issue.net 而不是 /etc/issue 

etc/motd:类似于布告栏信息(motd: message of the day的缩写)

注意:etc/issue和etc/motd的区别在于,/etc/issue的信息出现在login登录前,/etc/motd出现在登陆后。因为secureCRT实际上是输入账号口令后进入到命令行界面,所以那部分信息是在/etc/motd中编辑的。


1、etc/issue

下面也可以加上自定义的文字,比如“welcome”。

这个是etc/issue中的内容,各代码代表的含义如下:



因为我是使用的单位分配的虚拟机操作的linux系统,所以属于远程登录,应该遵循下面一小节的设置方法。

2、etc/motd

修改/etc/motd这个文件里的内容:



当再次连接登录程序时,显示画面为:


(三)bash的环境配置文件

网友总结:

/etc/profile,/etc/bashrc 是系统全局环境变量设定

~/.profile,~/.bashrc用户家目录下的私有环境变量设定

当登入系统时候获得一个shell进程时,其读取环境设定档有三步
1首先读入的是全局环境变量设定档/etc/profile,然后根据其内容读取额外的设定的文档,如
/etc/profile.d和/etc/inputrc
2然后根据不同使用者帐号,去其家目录读取~/.bash_profile,如果这读取不了就读取~/.bash_login,这个也读取不了才会读取
~/.profile,这三个文档设定基本上是一样的,读取有优先关系
3然后在根据用户帐号读取~/.bashrc
至于~/.profile与~/.bashrc的不区别
都具有个性化定制功能
~/.profile可以设定本用户专有的路径,环境变量,等,它只能登入的时候执行一次
~/.bashrc也是某用户专有设定文档,可以设定路径,命令别名,每次shell script的执行都会使用它一次

1、login 与 non-login

  • login需要完整的登录流程,不需要图形界面的,在shell中输入账户和密码;
  • non-login取得bash接口的方法不需要重复登录的举动。我平时使用的是这种non-login方法,在图形界面里打开shell,不需要再输入用户名和密码。

这两个取得bash的情况,读取的配置文件不一致。下面先记录两个只有login shell才会读取的配置文件

2、/etc/profile(login shell才会读)

文件设置的主要变量有:

  • PATH:会依据 UID 决定 PATH 变量要不要含有 sbin 的系统命令目录;
  • MAIL:依据账号配置好使用者的 mailbox 到 /var/spool/mail/账号名;
  • USER:根据用户的账号配置此一变量内容;
  • HOSTNAME:依据主机的 hostname 命令决定此一变量内容;
  • HISTSIZE:历史命令记录笔数。CentOS 5.x 配置为 1000 ;

每个使用者通过login shell登录时必须要访问的配置文件。bash的login shell登录所读取的整体环境配置文件只有/etc/profile,但是/etc/profile会调用其他的配置文件,这种操作方式使得bash操作接口变得非常友善。在调用外部数据时,西面的这些数据会依序被呼叫进来:

  • /etc/inputrc
    其实这个文件并没有被运行啦!/etc/profile 会主动的判断使用者有没有自定义输入的按键功能,如果没有的话, /etc/profile 就会决定配置『INPUTRC=/etc/inputrc』这个变量!此一文件内容为 bash 的热键啦、[tab]要不要有声音啦等等的数据! 因为鸟哥觉得 bash 默认的环境已经很棒了,所以不建议修改这个文件!

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

  • /etc/sysconfig/i18n
    这个文件是由 /etc/profile.d/lang.sh 呼叫进来的!这也是我们决定 bash 默认使用何种语系的重要配置文件! 文件里最重要的就是 LANG 这个变量的配置啦!我们在前面的 locale 讨论过这个文件啰! 自行回去瞧瞧先!

3、~/.bash_profile(login shell才会读)

注意:/etc/profile和~/.bash_profile被修改后,需要注销后再次登录,修改的内容才会生效,如果想立即生效,可以使用“source”或者“.”:source ~/.bashrc,就可以将刚刚配置的内容读到当下环境中

(四)终端机的环境配置:stty, set

像backspace可以删除字符,Ctrl c可以终止一个命令的运行等等,这种操作可以正常执行,是因为我们在登录终端的时候,它会自动的取得一些终端机的输入环境的配置。有两种方法:stty和set,用来修改终端机的环境配置。

1、stty

如果我们想要更改某种操作的“热键”,可以通过stty的方式。比如erase,向后删除字符(其实就是删除刚刚打印的字符),我先输入一串字符,按delete,可以删除,按Ctrl y没有反应,然后设置stty erase ^y,这时候^y就可以删除字符了,而按下delete,则显示如第二行,如果想恢复delete功能,则从新设置stty erase ^?,就可。


2、set

在学习env,set部分时,我们了解到,env可以查看所有环境变量及常见环境变量的设置,而set可以查看所有变量(环境变量和自定义变量)的设置。除此之外,set还可以帮助设置整个命令输入/输出的环境。如,记录历史命令,显示错误内容等。


例如,参数-u默认不启动,若启动后,当输入的变量是位置的,则会输出提示,否则,无提示,如上图所示。

还有其他的与终端机有关的环境配置文件,比如:etc/inputrc  etc/DIR_COLORS*  etc/termcap等等。但是bash环境设置的已经很好了,这里只是做了解,不建议更改。

(五)通配符与特殊符号

通配符:* ? [ ] [-] [^]

特殊符号:# \ / $ << <等等

五、数据流重定向

(一)什么是数据流重定向

1、standard ouptut 和 standard error output

将某个命令执行后应该出现在屏幕上的数据传输到其他地方,叫数据流重定向

“<”或者“>”代表覆盖,“<<”或者“>>”代表累加。

执行结果代码是“1”;错误信息代码是“2”

例如:

find /home -name .bashrc>list_right 2>list_error

正确结果输入到list_right,错误结果输入到list_error

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

  • find /home -name .bashrc 2>/dev/null 

    屏幕上只会显示正确的结果输入,error信息被抛弃

  • 两个信息放到一个文件里时

    find /home -name .bashrc 1>list 2>&1

    或者

    find /home -name .bashrc &>list

3、standard input:<和<<

  • 首先,cat也是一种创建文件的方法,具体如下:

    

    创建名为catfile1的文件,按下Ctrl d离开输入环境

  • 除了可以键盘内容输入,还可以用纯文本文件输入

    

    仍然需要以“cat >”开头,代表要创建文件;

    ls信息可以看出,两个文件的大小一模一样,像是复制。

  • <<

    终结符

 

(二)命令执行的判断依据:; , &&, ||

  • cmd;cmd;cmd 命令以此执行
  • cmd1 $$ cmd2:cmd1正确,则执行cmd2;若cmd1错误,则cmd2不执行(要么1,2;要不都不执行)
  • cmd1 || cmd2:cmd1正确,则不执行cmd2;若cmd2错误,则执行cmd1(要么1,要么2)
     
经典例题1:

       创建/tmp/abc/hehe这个文件,但是不清楚abc这个文件是否存在。

       ls /tmp/abc || mkdir /tmp/abc && touch /tmp/abc/hehe

经典例题2:

       以ls测试/tmp/vbirding是否存在,如果存在,则输出“exist”;如果不存在,则输出“not exist”

       ls /tmp/vbirding && echo "exist" || echo "not exist"

&&和 || 的顺序很重要,||左右放置肯定要执行的命令

六、管道命令

管道命令,与“连续执行命令”是不一样的。

管道命令仅会处理standard output,对于standard error output会忽略;

管道命令必须能够接收来自前一个命令的数据,成为standard input继续处理才行。

(一)选取命令:cut, grep

cut,是选取每一行的某一列或者几列

[root@www ~]# cut -d'分隔字符' -f fields <==用于有特定分隔字符
[root@www ~]# cut -c 字符区间            <==用于排列整齐的信息
选项与参数:
-d  :后面接分隔字符。与 -f 一起使用;
-f  :依据 -d 的分隔字符将一段信息分割成为数段,用 -f 取出第几段的意思;
-c  :以字符 (characters) 的单位取出固定字符区间;

范例一:将 PATH 变量取出,我要找出第五个路径。
[root@www ~]# echo $PATH
/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/X11R6/bin:/usr/games:
# 1 |    2   |  3  |    4    |       5      |     6        |    7

[root@www ~]# echo $PATH | cut -d ':' -f 5
# 如同上面的数字显示,我们是以『 : 』作为分隔,因此会出现 /usr/local/bin 
# 那么如果想要列出第 3 与第 5 呢?,就是这样:
[root@www ~]# echo $PATH | cut -d ':' -f 3,5

范例二:将 export 输出的信息,取得第 12 字符以后的所有字符串
[root@www ~]# export
declare -x HISTSIZE="1000"
declare -x INPUTRC="/etc/inputrc"
declare -x KDEDIR="/usr"
declare -x LANG="zh_TW.big5"
.....(其他省略).....
# 注意看,每个数据都是排列整齐的输出!如果我们不想要『 declare -x 』时,
# 就得这么做:

[root@www ~]# export | cut -c 12-
HISTSIZE="1000"
INPUTRC="/etc/inputrc"
KDEDIR="/usr"
LANG="zh_TW.big5"
.....(其他省略).....
# 知道怎么回事了吧?用 -c 可以处理比较具有格式的输出数据!
# 我们还可以指定某个范围的值,例如第 12-20 的字符,就是 cut -c 12-20 等等!

范例三:用 last 将显示的登陆者的信息中,仅留下用户大名
[root@www ~]# last
root   pts/1    192.168.201.101  Sat Feb  7 12:35   still logged in
root   pts/1    192.168.201.101  Fri Feb  6 12:13 - 18:46  (06:33)
root   pts/1    192.168.201.254  Thu Feb  5 22:37 - 23:53  (01:16)
# last 可以输出『账号/终端机/来源/日期时间』的数据,并且是排列整齐的

[root@www ~]# last | cut -d ' ' -f 1
# 由输出的结果我们可以发现第一个空白分隔的字段代表账号,所以使用如上命令:
# 但是因为 root   pts/1 之间空格有好几个,并非仅有一个,所以,如果要找出 
# pts/1 其实不能以 cut -d ' ' -f 1,2 喔!输出的结果会不是我们想要的。

grep,是筛选出符合条件(存在关键字)的行记录

[root@www ~]# grep [-acinv] [--color=auto] '搜寻字符串' filename
选项与参数:
-a :将 binary 文件以 text 文件的方式搜寻数据
-c :计算找到 '搜寻字符串' 的次数
-i :忽略大小写的不同,所以大小写视为相同
-n :顺便输出行号
-v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行!
--color=auto :可以将找到的关键词部分加上颜色的显示喔!

范例一:将 last 当中,有出现 root 的那一行就取出来;
[root@www ~]# last | grep 'root'

范例二:与范例一相反,只要没有 root 的就取出!
[root@www ~]# last | grep -v 'root'

范例三:在 last 的输出信息中,只要有 root 就取出,并且仅取第一栏
[root@www ~]# last | grep 'root' |cut -d ' ' -f1
# 在取出 root 之后,利用上个命令 cut 的处理,就能够仅取得第一栏啰!

范例四:取出 /etc/man.config 内含 MANPATH 的那几行
[root@www ~]# grep --color=auto 'MANPATH' /etc/man.config
....(前面省略)....
MANPATH_MAP     /usr/X11R6/bin          /usr/X11R6/man
MANPATH_MAP     /usr/bin/X11            /usr/X11R6/man
MANPATH_MAP     /usr/bin/mh             /usr/share/man
# 神奇的是,如果加上 --color=auto 的选项,找到的关键词部分会用特殊颜色显示喔!

(二)排序命令:sort, wc, uniq

sort排序,一般是以第一个的数据来排序,也可以指定使用哪一列排序;

[root@www ~]# sort [-fbMnrtuk] [file or stdin]
选项与参数:
-f  :忽略大小写的差异,例如 A 与 a 视为编码相同;
-b  :忽略最前面的空格符部分;
-M  :以月份的名字来排序,例如 JAN, DEC 等等的排序方法;
-n  :使用『纯数字』进行排序(默认是以文字型态来排序的);
-r  :反向排序;
-u  :就是 uniq ,相同的数据中,仅出现一行代表;
-t  :分隔符,默认是用 [tab] 键来分隔;
-k  :以那个区间 (field) 来进行排序的意思

范例一:个人账号都记录在 /etc/passwd 下,请将账号进行排序。
[root@www ~]# cat /etc/passwd | sort
adm:x:3:4:adm:/var/adm:/sbin/nologin
apache:x:48:48:Apache:/var/www:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
# 鸟哥省略很多的输出~由上面的数据看起来, sort 是默认『以第一个』数据来排序,
# 而且默认是以『文字』型态来排序的喔!所以由 a 开始排到最后啰!

范例二:/etc/passwd 内容是以 : 来分隔的,我想以第三栏来排序,该如何?
[root@www ~]# cat /etc/passwd | sort -t ':' -k 3
root:x:0:0:root:/root:/bin/bash
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
# 看到特殊字体的输出部分了吧?怎么会这样排列啊?呵呵!没错啦~
# 如果是以文字型态来排序的话,原本就会是这样,想要使用数字排序:
# cat /etc/passwd | sort -t ':' -k 3 -n
# 这样才行啊!用那个 -n 来告知 sort 以数字来排序啊!

范例三:利用 last ,将输出的数据仅取账号,并加以排序
[root@www ~]# last | cut -d ' ' -f1 | sort

uniq:有时候会有过多重复结果,这时候可以使用uniq,去重

[root@www ~]# uniq [-ic]
选项与参数:
-i  :忽略大小写字符的不同;
-c  :进行计数

范例一:使用 last 将账号列出,仅取出账号栏,进行排序后仅取出一位;
[root@www ~]# last | cut -d ' ' -f1 | sort | uniq

范例二:承上题,如果我还想要知道每个人的登陆总次数呢?
[root@www ~]# last | cut -d ' ' -f1 | sort | uniq -c
      1
     12 reboot
     41 root
      1 wtmp
# 从上面的结果可以发现 reboot 有 12 次, root 登陆则有 41 次!
# wtmp 与第一行的空白都是 last 的默认字符,那两个可以忽略的!

wc:word count 可以用来统计文件中有多少行(-l),英文单字(-w)或字符(-m)

[root@www ~]# wc [-lwm]
选项与参数:
-l  :仅列出行;
-w  :仅列出多少字(英文单字);
-m  :多少字符;

范例一:那个 /etc/man.config 里面到底有多少相关字、行、字符数?
[root@www ~]# cat /etc/man.config | wc 
    141     722    4617
# 输出的三个数字中,分别代表: 『行、字数、字符数』

范例二:我知道使用 last 可以输出登陆者,但是 last 最后两行并非账号内容,
        那么请问,我该如何以一行命令串取得这个月份登陆系统的总人次?
[root@www ~]# last | grep [a-zA-Z] | grep -v 'wtmp' | wc -l 
# 由于 last 会输出空白行与 wtmp 字样在最底下两行,因此,我利用
# grep 取出非空白行,以及去除 wtmp 那一行,在计算行数,就能够了解啰!

(三)双向重定向:tee

双向重定向,即命令的输出,既存入文件或设备中,又能在屏幕上显示

last | tee -a last.list


也可以对输出进行选择性输出


-a代表叠加,不加选项代表覆盖

(四)字符转换命令:tr, col, join, paste, expand

1. tr 删除要在屏幕上显示的文字中的信息或者进行文字替换

[root@www ~]# tr [-ds] SET1 ...
选项与参数:
-d  :删除信息当中的 SET1 这个字符串;
-s  :取代掉重复的字符!


注意:原文件中的内容不变,变化的仅仅是当次显示的内容

2. col

[root@www ~]# col [-xb]
选项与参数:
-x  :将 tab 键转换成对等的空格键
-b  :在文字内有反斜杠 (/) 时,仅保留反斜杠最后接的那个字符


我在创建testtr.txt这个测试文件到时候,使用了很多tab,但是在利用more查看文件内容时,所有的tab空格位置,显示的是一堆“^I”,看起来影响美观,不够直接,所以可以使用col -x的方法,将tab替换回空格
范例二:将 col 的 man page 转存成为 /root/col.man 的纯文本档
[root@www ~]# man col > /root/col.man
[root@www ~]# vi /root/col.man
COL(1)          BSD General Commands Manual               COL(1)

N^HNA^HAM^HME^HE
     c^Hco^Hol^Hl - filter reverse line feeds from input

S^HSY^HYN^HNO^HOP^HPS^HSI^HIS^HS
     c^Hco^Hol^Hl [-^H-b^Hbf^Hfp^Hpx^Hx] [-^H-l^Hl _^Hn_^Hu_^Hm]
# 你没看错!由于 man page 内有些特殊按钮会用来作为类似特殊按键与颜色显示,
# 所以这个文件内就会出现如上所示的一堆怪异字符(有 ^ 的)

[root@www ~]# man col | col -b > /root/col.man

这个范例,或许Redhat7和Redhat6存在差异,在Redhat7中,vi查看col.man文件,未出现乱码特殊字符,显示非常正常。

3. join  将两个有相同数据的文件进行相连

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

范例一:用 root 的身份,将 /etc/passwd 与 /etc/shadow 相关数据整合成一栏
[root@www ~]# head -n 3 /etc/passwd /etc/shadow
==> /etc/passwd <==
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

==> /etc/shadow <==
root:$1$/3AQpE5e$y9A/D0bh6rElAs:14120:0:99999:7:::
bin:*:14126:0:99999:7:::
daemon:*:14126:0:99999:7:::
# 由输出的数据可以发现这两个文件的最左边字段都是账号!且以 : 分隔

[root@www ~]# join -t ':' /etc/passwd /etc/shadow
root:x:0:0:root:/root:/bin/bash:$1$/3AQpE5e$y9A/D0bh6rElAs:14120:0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin:*:14126:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:14126:0:99999:7:::
# 透过上面这个动作,我们可以将两个文件第一字段相同者整合成一行!
# 第二个文件的相同字段并不会显示(因为已经在第一行了嘛!)

范例二:我们知道 /etc/passwd 第四个字段是 GID ,那个 GID 记录在 
        /etc/group 当中的第三个字段,请问如何将两个文件整合?
[root@www ~]# head -n 3 /etc/passwd /etc/group
==> /etc/passwd <==
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

==> /etc/group <==
root:x:0:root
bin:x:1:root,bin,daemon
daemon:x:2:root,bin,daemon
# 从上面可以看到,确实有相同的部分喔!赶紧来整合一下!

[root@www ~]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group
0:root:x:0:root:/root:/bin/bash:root:x:root
1:bin:x:1:bin:/bin:/sbin/nologin:bin:x:root,bin,daemon
2:daemon:x:2:daemon:/sbin:/sbin/nologin:daemon:x:root,bin,daemon
# 同样的,相同的字段部分被移动到最前面了!所以第二个文件的内容就没再显示。
# 请读者们配合上述显示两个文件的实际内容来比对!

有关联的数据,是用约定的(比如默认的空格,设定的分号等等)符号进行分隔的,前部分是第一个文件中的数据,后部分是第二个文件中的数据,一般情况下,第一个文件数据全部展示,第二个文件中,关联数据(即重复数据)不显示,扣掉后,其余内容全部显示。

在使用 join 之前,你所需要处理的文件应该要事先经过排序 (sort) 处理

4. paste 基本的粘贴

将两个文件,按照原始数据顺序作拼接,默认中间用Tab分隔


5. expand 将tab替换为若干个空格

我将 [tab] 按键配置成 6 个字符的话?
[root@www ~]# grep '^MANPATH' /etc/man.config | head -n 3 | \
>  expand -t 6 - | cat -A
MANPATH     /usr/man$
MANPATH     /usr/share/man$
MANPATH     /usr/local/man$
123456123456123456.....
# 仔细看一下上面的数字说明,因为我是以 6 个字符来代表一个 [tab] 的长度,所以,
# MAN... 到 /usr 之间会隔 12 (两个 [tab]) 个字符喔!如果 tab 改成 9 的话,
# 情况就又不同了!这里也不好理解~您可以多配置几个数字来查阅就晓得!

6. split  文件分割


-b 按照大小分割 例如 300k

-l 按照行分割,后面跟着行数

注意:要在分割后文件所在的文件夹执行split操作,才能成功。

7. xarg

8. 减号 -

七、习题

情境模拟题一:由于 ~/.bash_history 仅能记录命令,我想要在每次注销时都记录时间,并将后续的命令 50 笔记录下来, 可以如何处理?
答:其实处理的方式非常简单,我们可以了解 date 可以输出时间,而利用 ~/.myhistory 来记录所有历史记录, 而目前最新的 50 笔历史记录可以使用 history 50 来显示,故可以修改 ~/.bash_logout 成为底下的模样:

[root@www ~]# vim ~/.bash_logout
date >> ~/.myhistory
history 50 > > ~/.myhistory
clear

注意:logout是注销的意思,平时直接关闭linux虚拟机窗口,是exit,即断开连接。

每次注销shell的时候,才会执行bash_logout。


去查看.bash_logout的文件权限,显示的是三种身份用户的对该文件的权限,都没有“x”执行权限,所以从用户角度是不能执行该文件的,而在注销时,会由系统调用。

简答练习题:

1、在 Linux 上可以找到哪些 shell(举出三个) ?那个文件记录可用的 shell ?而 Linux 默认的 shell 是?

答:在/etc/shells中可以查看可用的shell


使用不同shell执行文件的方法:bash script或者sh script或者csh script,即使此时用户对文件script没有执行“x”权限,也可以;当给script赋予“x”权限后,可以通过绝对路径或者相对路径执行文件。


2、在 shell 环境下,有个提示字符 (prompt),他可以修改吗?要改什么?默认的提示字符内容是?

  答:可以修改的,改 PS1 这个变量,这个 PS1 变量的默认内容为:『[\u@\h \W]\$』  

     注意:修改变量值时,注意双引号,单引号的区别


3、如何显示 HOME 这个环境变量?

      答:echo $HOME

      关于linux用户信息:在根目录下有两个与用户相关的目录,/root和/home,目前登录时默认使用的是超级用户身份,所以在此身份下的各种相关文件是放在了/root目录下,此时$HOME,显示的是/root,在/root下也存放着类似于~/.bash_history文件,记录了以/root身份操作时的命令记录;假若我su - zqtest切换到另一个用户,那么使用$HOME时,显示的是/home/zqtest,同样,在这个用户的home用户中,存放了记录它操作的历史命令行~/.bash_history


4、如何配置一个变量名称为 name 内容为 It's my name ?

第一条命令,错误在于等号两侧加了空格,系统从左往右解析输入语句时,遇到了空格,就把name当做了一条命令去搜索bin可执行文件,么有找到,所以报错


5、 如何将 last 的结果中,独立出账号,并且印出曾经登陆过的账号?

如果不排序直接unique,只是将连续的重复值去掉,注意看结果,出现了多次的root,reboot等等


正确操作是先sort排序,再unique

6、如何秀出 /bin 底下,文件名为四个字符的文件?

答:ls -al /bin/ a*

注意:在/bin这个文件夹下,在写路径时,/bin/ 后面的这个/非常重要,没有的话,显示的是根目录“/”下的文件详情











猜你喜欢

转载自blog.csdn.net/vicky198/article/details/79709864
今日推荐