/bin/bash 是 Linux 预设的 shell
bash可以记忆使用过的指令
~/.bash_history 记录的是前一次登入以前所执行过的指令
命令与档案补全功能: ([tab] 按键的好处)
连续按两次 [tab]列出所有提示
命令别名设定功能: (alias)
alias lm='ls -al'
工作控制、前景背景控制
程序化脚本: (shell scripts)
通配符: (Wildcard)
[root@www ~]# type [-tpa] name #选项与参数: :不加任何选项与参数时,type 会显示出 name 是外部指令还是 bash 内建指令
指令的下达
就利用『 \[Enter] 』来将 [Enter] 这个按键『跳脱!』开来,让 [Enter] 按键不再具有『开始执行』的功能!好让指令可以继续在下一行输入。
『变量就是以一组文字或符号等,来取代一些设定或者是一串保留的数据!』
由于系统需要一些变量来提供他数据的存取 ,所以就有一些所谓的『环境变量』 需要来读入系统中了!
环境变量例如 PATH、HOME、MAIL、SHELL
环境变量通常以大写字符来表示
变量在被取用时,前面必须要加上钱字号『 $ 』才行
变数的取用: echo
[root@www ~]# echo $PATH
用『等号(=)』连接变量与他的内容『设定』或者是『修改』 某个变量的内容
变量的设定规则:
1. 变量与变量内容以一个等号『=』来连结
2. 等号两边不能直接接空格符
3. 变量名称只能是英文字母与数字,但是开头字符不能是数字
4. 变量内容若有空格符可使用双引号『"』或单引号『'』将变量内容结合起来,但双引号内的特殊字符如 $ 等,可以保有原本的特性;单引号内的特殊字符则仅为一般字符。
5. 可用跳脱字符『 \ 』将特殊符号(如 [Enter], $, \, 空格符, '等)变成一般字符;
6. 在一串指令中,还需要藉由其他的指令提供的信息,可以使用反单引号『`指令`』或 『$(指令)』
7. 若该变量为扩增变量内容时,则可用 "$变量名称" 或 ${变量} 累加内容,如下所示: 『PATH="$PATH":/home/bin』
8. 若该变量需要在其他子程序执行,则需要以 export 来使变量变成环境变量: 『export PATH』
9. 通常大写字符为系统默认变量,自行设定变量可以使用小写字符,方便判断 (纯粹依照使用者兴趣与嗜好) ;
10.取消变量的方法为使用 unset :『unset 变量名称』例如取消 myname 的设定: 『unset myname』
『子程序』:
就是说,在我目前这个 shell 的情况下,去启用另一个新的 shell ,新的那个 shell 就是子程序啦!
在一般的状态下,父程序的自定义变量是无法在子程序内使用的。但是透过 export 将变量变成环境变量后,就能够在子程序底下应用了!
范例:如何进入到您目前核心的模块目录?
[root@www ~]# cd /lib/modules/`uname -r`/kernel
利用 uname -r 这个指令取得版本信息。
范例一:列出目前的 shell 环境下的所有环境变量与其内容。
[root@www ~]# env
PS1='[\u@\h \W]\$ ' <== PS1 就厉害了。这个是命令提示字符,也就是我们常见的 [root@www ~]# 或 [dmtsai ~]$ 的设定值啦!可以更动的!
$ <== 目前这个 shell 所使用的 PID
? <== 刚刚执行完指令的回传值。
将自定义变量变成环境变量
[root@www ~]# export 变量名称
[root@www ~]# locale
[root@www ~]# cat /etc/sysconfig/i18n
read命令
[root@www ~]# read atest This is a test <==此时光标会等待你输入!
declare / typeset 是一样的功能,宣告变量的类型
[root@www ~]# declare -i sum=100+300+50
数组 (array) 变量类型
var[index]=content
[root@www ~]# var[1]="small min"
[root@www ~]# var[2]="big min"
[root@www ~]# var[3]="nice min"
[root@www ~]# echo "${var[1]}, ${var[2]}, ${var[3]}"
[root@www ~]# ulimit [-SHacdfltu] [配额]
变量内容的删除与取代:
『从前面开始删除变量内容』:
[root@www ~]# path=${PATH}
[root@www ~]# echo ${path#/*kerberos/bin:} #要将/usr/kerberos/sbin:/usr/kerberos/bin:两个目录删除掉
[root@www ~]# echo ${path##/*:} #从头删除掉目录就是介于斜线 (/) 到冒号 (:) 之间的数据
# :符合取代文字的『最短的』那一个;
##:符合取代文字的『最长的』那一个
『从后面向前删除变量内容』:
[root@www ~]# echo ${path%:*bin}
# :符合取代文字的『最短的』那一个;
##:符合取代文字的『最长的』那一个
『取代』:
[root@www ~]# echo ${path/sbin/SBIN} #将 path 的变量内容内的第一个 sbin 取代成大写 SBIN
[root@www ~]# echo ${path//sbin/SBIN} #将 path 的变量内容内的所有的sbin 取代成大写 SBIN
[root@www ~]# username="vbird tsai"
[root@www ~]# username=${username-root} #因为 username 已经设定了(为空),所以使用旧有的设定而不以 root 取代
[root@www ~]# username=${username:-root} #加上『 : 』后若变量内容为空或者是未设定,都能够以后面的内容替换!
如果你想要将旧变量内容也一起替换掉的话,那么就使用等号 (=) 吧:
[root@www ~]# unset str; var=${str=newvar}
如果旧变量不存在时,整个测试就告知我『有错误』,此时就能够使用问号『 ? 』
[root@www ~]# unset str; var=${str?无此变量}
-bash: str: 无此变量
命令别名设定: alias, unalias:
[root@www ~]# alias lm='ls -l | more' #立刻多出了一个可以执行的指令喔!这个指令名称为 lm
[root@www ~]# alias rm='rm -i' #命令别名的设定还可以取代既有的指令
目前有哪些的命令别名:
[root@www ~]# alias
取消命令别名unalias:
[root@www ~]# unalias lm
历史命令:history (查询我们曾经下达过的指令)
[root@www ~]# !number
[root@www ~]# !command
[root@www ~]# !!
参数: number :执行第几笔指令的意思; command :由最近的指令向前搜寻『指令串开头为 command』的那个指令,并执行; !! :就是执行上一个指令(相当于按↑按键后,按 Enter)
bash 的进站与欢迎讯息: /etc/issue, /etc/motd
除了 /etc/issue 之外还有个 /etc/issue.net 呢!这是啥?这个是提供给 telnet 这个远程登录程序用的
login shell:
其实只会读取这两个配置文件:
1. /etc/profile:这是系统整体的设定,你最好不要修改这个档案;
2. ~/.bash_profile 或 ~/.bash_login 或 ~/.profile:属于使用者个人设定,你要改自己的数据,就写入这里!
在 CentOS 5.x 默认的情况下, 底下这些数据会依序的被呼叫进来:
/etc/inputrc #此一档案内容为 bash 的热键啦、[tab]要不要有声音啦等等的数据!
/etc/profile.d/*.sh #这个目录底下的档案规范了 bash 操作接口的颜色、 语系、ll 与 ls 指令的命令别名、vi 的命令别名、which 的命令别名等等
/etc/sysconfig/i18n #由 /etc/profile.d/lang.sh 呼叫进来的!决定 bash 预设使用何种语系的重要配置文件! 最重要的就是 LANG 这个变量啦!
~/.bash_profile
~/.bash_login
~/.profile
如果 ~/.bash_profile 不存在才会去读取 ~/.bash_login,而前两者都不存在才会读取 ~/.profile
[root@www ~]# cat ~/.bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then <==底下这三行在判断并读取 ~/.bashrc
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin <==底下这几行在处理个人化设定
export PATH
unset USERNAME
source
[root@www ~]# source 配置文件档名
[root@www ~]# source ~/.bashrc <==底下这两个指令是一样的!
[root@www ~]# . ~/.bashrc
利用 source 或小数点 (.) 都可以将配置文件的内容读进来目前的 shell 环境中!
non-login shell:
~/.bashrc
[root@www ~]# cat ~/.bashrc
# .bashrc
# User specific aliases and functions
alias rm='rm -i' <==使用者的个人设定
alias cp='cp -i'
alias mv='mv -i'
# Source global definitions
if [ -f /etc/bashrc ]; then <==整体的环境设定
. /etc/bashrc
fi
其他配置文件
/etc/man.config
这个档案规定了下达 man 的时候,该去哪里查看数据的路径设定!
~/.bash_history
历史命令就记录在这里
~/.bash_logout
这个档案则记录了『当我注销 bash 后,系统再帮我做完什么动作后才离开』的意思。
终端机的环境设定: stty, set
[root@www ~]# stty -a #列出所有的按键与按键内容
^ 表示 [Ctrl]
除了 stty 之外,其实我们的 bash 还有自己的一些终端机设定值呢!那就是利用 set 来设定的!
[root@www ~]# set [-uvCHhmBx]
选项与参数: -u :预设不启用。若启用后,当使用未设定变量时,会显示错误讯息; -v :预设不启用。若启用后,在讯息被输出前,会先显示讯息的原始内容; -x :预设不启用。若启用后,在指令被执行前,会显示指令内容(前面有 ++ 符号) -h :预设启用。与历史命令有关; -H :预设启用。与历史命令有关; -m :预设启用。与工作管理有关; -B :预设启用。与刮号 [] 的作用有关; -C :预设不启用。若使用 > 等,则若档案存在时,该档案不会被覆盖。
其实我们还有其他的按键设定功能呢!就是在前一小节提到的 /etc/inputrc 这个档案里面设定
通配符
* 代表『 0 个到无穷多个』任意字符
? 代表『一定有一个』任意字符
[ ] 同样代表『一定有一个在括号内』的字符(非任意字符)。例如 [abcd] 代表『一定有一个字符, 可能是 a, b, c, d 这四个任何一个』
[ - ] 若有减号在中括号内时,代表『在编码顺序内的所有字符』。例如 [0-9] 代表 0 到 9 之间的所有数字,因为数字的语系编码是连续的!
[^ ] 若中括号内的第一个字符为指数符号 (^) ,那表示『反向选择』,例如 [^abc] 代表 一定有一个字符,只要是非 a, b, c 的其他字符就接受的意思。
bash 环境中的特殊符号
# 批注符号:这个最常被使用在 script 当中,视为说明!在后的数据均不执行
\ 跳脱符号:将『特殊字符或通配符』还原成一般字符
| 管线 (pipe):分隔两个管线命令的界定(后两节介绍);
; 连续指令下达分隔符:连续性命令的界定 (注意!与管线命令并不相同)
~ 用户的家目录
$ 取用变数前导符:亦即是变量之前需要加的变量取代值
& 工作控制 (job control):将指令变成背景下工作
! 逻辑运算意义上的『非』 not 的意思!
/ 目录符号:路径分隔的符号
>, >> 数据流重导向:输出导向,分别是『取代』与『累加』
<, << 数据流重导向:输入导向
' ' 单引号,不具有变量置换的功能
" " 具有变量置换的功能!
` ` 两个『 ` 』中间为可以先执行的指令,亦可使用 $( )
( ) 在中间为子 shell 的起始与结束
{ } 在中间为命令区块的组合!
数据流重导向
1>、1>>、2>、2>>
数据流重导向就是将某个指令执行后应该要出现在屏幕上的数据, 给他传输到其他的地方。
[root@www ~]# ll / > ~/rootfile #观察你的系统根目录 (/) 下各目录的文件名、权限与属性,并记录下来
[dmtsai@www ~]$ find /home -name .bashrc > list_right 2> list_error #将 stdout 与 stderr 分存到不同的档案去
/dev/null 垃圾桶黑洞装置与特殊写法
[dmtsai@www ~]$ find /home -name .bashrc 2> /dev/null #将错误讯息忽略掉而不显示或储存
#将指令的数据全部写入名为 list 的档案中,以下两种写法都正确:
[dmtsai@www ~]$ find /home -name .bashrc > list 2>&1
[dmtsai@www ~]$ find /home -name .bashrc &> list
standard input : < 与 <<
将原本需要由键盘输入的数据,改由档案内容来取代
[root@www ~]# cat > catfile #利用 cat 指令来建立一个档案的简单流程
testing cat file test
<==这里按下 [ctrl]+d 来离开
[root@www ~]# cat > catfile < ~/.bashrc #这两个档案的大小会一模一样!几乎像是使用 cp 来复制一般!
<< 代表的是『结束的输入字符』
例如:[root@www ~]# cat > catfile << "eof" # 输入这关键词,立刻就结束而不需要输入 [ctrl]+d
cmd ; cmd (不考虑指令相关性的连续指令下达)
[root@www ~]# sync; sync; shutdown -h now #在关机的时候我希望可以先执行两次 sync 同步化写入磁盘后才 shutdown 计算机
$? (指令回传值) 与 && 或 ||
cmd1 && cmd2 1. 若 cmd1 执行完毕且正确执行($?=0),则开始执行 cmd2。 2. 若 cmd1 执行完毕且为错误 ($?≠0),则 cmd2 不执行。
cmd1 || cmd2 1. 若 cmd1 执行完毕且正确执行($?=0),则 cmd2 不执行。 2. 若 cmd1 执行完毕且为错误 ($?≠0),则开始执行 cmd2。
管线命令 (pipe)
每个管线后面接的第一个数据必定是『指令』喔!而且这个指令必须要能够接受 standard input 的数据才行,这样的指令才可以是为『管线命令』
[root@www ~]# ls -al /etc | less
撷取命令: cut, grep
cut 主要的用途在于将『同一行里面的数据进行分解!』最常使用在分析一些数据或文字数据的时候!
[root@www ~]# echo $PATH | cut -d ':' -f 5 #将 PATH 变量取出,我要找出第五个路径。
[root@www ~]# echo $PATH | cut -d ':' -f 3,5 #要列出第 3 与第 5 呢
[root@www ~]# export | cut -c 12- # 取得第 12 字符以后的所有字符串
# 我们还可以指定某个范围的值,例如第 12-20 的字符,就是 cut -c 12-20 等等
[root@www ~]# last | cut -d ' ' -f 1 #用 last 将显示的登入者的信息中,仅留下用户大名
cut 在处理多空格相连的数据时,可能会比较吃力一点。
grep
[root@www ~]# grep [-acinv] [--color=auto] '搜寻字符串' filename
选项与参数: -a :将 binary 档案以 text 档案的方式搜寻数据 -c :计算找到 '搜寻字符串' 的次数 -i :忽略大小写的不同,所以大小写视为相同 -n :顺便输出行号 -v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行! --color=auto :可以将找到的关键词部分加上颜色的显示喔!
[root@www ~]# last | grep 'root'
[root@www ~]# last | grep -v 'root'
[root@www ~]# last | grep 'root' |cut -d ' ' -f1
排序命令: 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) 来进行排序的意思
[root@www ~]# cat /etc/passwd | sort
[root@www ~]# cat /etc/passwd | sort -t ':' -k 3 #/etc/passwd 内容是以 : 来分隔的,我想以第三栏来排序
[root@www ~]# last | cut -d ' ' -f1 | sort #利用 last ,将输出的数据仅取账号,并加以排序
uniq
[root@www ~]# uniq [-ic]
选项与参数: -i :忽略大小写字符的不同; -c :进行计数
[root@www ~]# last | cut -d ' ' -f1 | sort | uniq #使用 last 将账号列出,仅取出账号栏,进行排序后仅取出一位;
[root@www ~]# last | cut -d ' ' -f1 | sort | uniq -c #承上题,如果我还想要知道每个人的登入总次数
wc
[root@www ~]# wc [-lwm]
选项与参数: -l :仅列出行; -w :仅列出多少字(英文单字); -m :多少字符;
[root@www ~]# cat /etc/man.config | wc # 输出的三个数字中,分别代表: 『行、字数、字符数』
[root@www ~]# last | grep [a-zA-Z] | grep -v 'wtmp' | wc -l
tee
[root@www ~]# tee [-a] file
选项与参数: -a :以累加 (append) 的方式,将数据加入 file 当中!
[root@www ~]# last | tee last.list | cut -d " " -f1 # 这个范例可以让我们将 last 的输出存一份到 last.list 档案中
[root@www ~]# ls -l / | tee -a ~/homefile | more # 要注意! tee 后接的档案会被覆盖,若加上 -a 这个选项则能将讯息累加。
字符转换命令: tr, col, join, paste, expand
tr
[root@www ~]# tr [-ds] SET1 ...
选项与参数: -d :删除讯息当中的 SET1 这个字符串; -s :取代掉重复的字符!
[root@www ~]# last | tr '[a-z]' '[A-Z]' #将 last 输出的讯息中,所有的小写变成大写字符
[root@www ~]# cat /etc/passwd | tr -d ':' #将 /etc/passwd 输出的讯息中,将冒号 (:) 删除
范例三:将 /etc/passwd 转存成 dos 断行到 /root/passwd 中,再将 ^M 符号删除
[root@www ~]# cp /etc/passwd /root/passwd && unix2dos /root/passwd
[root@www ~]# file /etc/passwd /root/passwd
[root@www ~]# cat /root/passwd | tr -d '\r' > /root/passwd.linux
col
[root@www ~]# col [-xb]
选项与参数: -x :将 tab 键转换成对等的空格键 -b :在文字内有反斜杠 (/) 时,仅保留反斜杠最后接的那个字符
[root@www ~]# cat /etc/man.config | col -x | cat -A | more #[tab] 按键会被取代成为空格键
[root@www ~]# man col > /root/col.man #将 col 的 man page 转存成为 /root/col.man 的纯文本档
join
主要是在处理『两个档案当中,有 "相同数据" 的那一行,才将他加在一起』
[root@www ~]# join [-ti12] file1 file2
选项与参数: -t :join 默认以空格符分隔数据,并且比对『第一个字段』的数据, 如果两个档案相同,则将两笔数据联成一行,且第一个字段放在第一个! -i :忽略大小写的差异; -1 :这个是数字的 1 ,代表『第一个档案要用那个字段来分析』的意思; -2 :代表『第二个档案要用那个字段来分析』的意思。
[root@www ~]# join -t ':' /etc/passwd /etc/shadow #用 root 的身份,将 /etc/passwd 与 /etc/shadow 相关数据整合成一栏
[root@www ~]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group #我们知道 /etc/passwd 第四个字段是 GID ,那个 GID 记录在 /etc/group 当中的第三个字段,将两个档案整合
需要特别注意的是,在使用 join 之前,你所需要处理的档案应该要事先经过排序 (sort) 处理!
paste
直接『将两行贴在一起,且中间以 [tab] 键隔开』而已
[root@www ~]# paste [-d] file1 file2
选项与参数: -d :后面可以接分隔字符。预设是以 [tab] 来分隔的!
- :如果 file 部分写成 - ,表示来自 standard input 的资料的意思.
[root@www ~]# paste /etc/passwd /etc/shadow #将 /etc/passwd 与 /etc/shadow 同一行贴在一起
[root@www ~]# cat /etc/group|paste /etc/passwd /etc/shadow -|head -n 3 #先将 /etc/group 读出(用 cat),然后与范例一贴上一起!且仅取出前三行
expand
这玩意儿就是在将 [tab] 按键转成空格键啦
[root@www ~]# expand [-t] file
选项与参数: -t :后面可以接数字。一般来说,一个 tab 按键可以用 8 个空格键取代。
[root@www ~]# grep '^MANPATH' /etc/man.config | head -n 3 | expand -t 6 - | cat -A
分割命令: split
他可以帮你将一个大档案,依据档案大小或行数来分割,就可以将大档案分割成为小档案了!
[root@www ~]# split [-bl] file PREFIX
选项与参数: -b :后面可接欲分割成的档案大小,可加单位,例如 b, k,
m 等; -l :以行数来进行分割。 PREFIX :代表前导符的意思,可作为分割档案的前导文字.
[root@www tmp]# cat termcap* >> termcapback #将上面的三个小档案合成一个档案,档名为 termcapback
[root@www tmp]# ls -al / | split -l 10 - lsroot #使用 ls -al / 输出的信息中,每十行记录成一个档案
参数代换: xargs
[root@www ~]# xargs [-0epn] command
参数: -0 :如果输入的 stdin 含有特殊字符,例如 `, \, 空格键等等字符时,这个 -0 参数 可以将他还原成一般字符。这个参数可以用于特殊状态喔! -e :这个是 EOF (end of file) 的意思。后面可以接一个字符串,当 xargs 分析到 这个字符串时,就会停止继续工作! -p :在执行每个指令的 argument 时,都会询问使用者的意思; -n :后面接次数,每次 command 指令执行时,要使用几个参数的意思。看范例三。 当 xargs 后面没有接任何的指令时,默认是以 echo 来进行输出喔!
[root@www ~]# cut -d':' -f1 /etc/passwd |head -n 3| xargs finger #将 /etc/passwd 内的第一栏取出,仅取三行,使用 finger 这个指令将每个 账号内容秀出来
[root@www ~]# cut -d':' -f1 /etc/passwd |head -n 3| xargs -p finger #同上,但是每次执行 finger 时,都要询问使用者是否动作?
[root@www ~]# cut -d':' -f1 /etc/passwd | xargs -p -n 5 finger #将所有的 /etc/passwd 内的账号都以 finger 查阅,但一次仅查阅五个账号
[root@www ~]# cut -d':' -f1 /etc/passwd | xargs -p -e'lp' finger #同上,但是当分析到 lp 就结束这串指令
会使用 xargs 的原因是, 很多指令其实并不支持管线命令,因此我们可以透过 xargs 来提供该指令引用 standard input 之用
错误示范:[root@www ~]# find /sbin -perm +7000 | ls -l #找出 /sbin 底下具有特殊权限的档名,并使用 ls -l 列出详细属性(因为 ll (ls) 并不是管线命令的原因)
正确示范:[root@www ~]# find /sbin -perm +7000 | xargs ls -l #找出 /sbin 底下具有特殊权限的档名,并使用 ls -l 列出详细属性
关于减号 - 的用途
在管线命令当中,常常会使用到前一个指令的 stdout 作为这次的 stdin,某些指令需要用到文件名 (例如 tar) 来进行处理时,该 stdin 与 stdout 可以利用减号 "-" 来替代
[root@www ~]# tar -cvf - /home | tar -xvf - #『我将 /home 里面的档案给他打包,但打包的数据不是纪录到档案,而是传送到 stdout; 经过管线后,将 tar -cvf - /home 传送给后面的 tar -xvf - 』。后面的这个 - 则是取用前一个指令的 stdout, 因此,我们就不需要使用 file 了