认识与学习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、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 :在文字内有反斜杠 (/) 时,仅保留反斜杠最后接的那个字符
范例二:将 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/ 后面的这个/非常重要,没有的话,显示的是根目录“/”下的文件详情 |