内容源于: 鸟哥的linux私房菜
链接如下:
Shell 的变量功能
Bash shell 的操作环境
数据流重导向 (Redirection)
管线命令 (pipe)
命令,重导向和管道 [命令][重导向][管道] bash [变量操作命名][变量内容操作][通配符与特殊符号]
[命令][重导向][管道]
我们通过 Shell 将我们的命令发给 Kernel, Kernel 再控制硬件完成我的工作
命令说明
命令列模式里面下达命令时,会有两种主要的情况:
- 一种是该命令会直接显示结果然后回到命令提示字符等待下一个命令的输入;
- 一种是进入到该命令的环境,直到结束该命令才回到命令提示字符的环境。
我们以一个简单的图示来说明:
命令的搜索顺序
- 以相对/绝对路径运行命令,例如『 /bin/ls 』或『 https://www.cnblogs.com/kzang/articles/ls 』;
- 由 alias 找到该命令来运行;
- 由 bash 内建的 (builtin) 命令来运行;
- 透过 $PATH 这个变量的顺序搜寻到的第一个命令来运行.
命令运行的判断依据: ; , &&, ||
- 『若前一个命令运行的结果为正确,在 Linux 底下会回传一个 $? = 0 的值』
范例三:我不清楚 /tmp/abc 是否存在,但就是要创建 /tmp/abc/hehe 文件[root@www ~]# ls /tmp/abc || mkdir /tmp/abc && touch /tmp/abc/hehe
数据流重导向就是将某个命令运行后应该要出现在屏幕上的数据, 给他传输到其他的地方.
下面用图来说明下重导向与不重导向的区别:
(从左向右:①不重导向的,②将标准输出和标准错误输出的数据重导向到文件中,③将标准输入用文件代替; 当然也可以在一个命令中即使用标准输入的重导向又使用标准输出的重导向)
- 标准输出『命令运行所回传的正确的信息』
- 标准错误输出『 命令运行失败后,所回传的错误信息』
- 标准输入 (stdin) :代码为 0 ,使用 < 或 << ;
- 标准输出 (stdout):代码为 1 ,使用 > 或 >> ;
- 标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ;
符号说明:
> :以覆盖的方式,将正确的数据输出到指定的文件或装置上
>> :以累加的方式,将错误信息输出到指定的文件或装置上< :将原本需要由键盘输入的数据,改由文件内容来取代<< :结束的输入字符
范例一:利用 cat 命令来创建一个文件的简单流程[root@www ~]# cat > catfiletestingcat file test
<==这里按下 [ctrl]+d 来离开
[root@www ~]# cat catfiletestingcat file test
范例二:用 stdin 取代键盘的输入以创建新文件的简单流程[root@www ~]# cat > catfile < ~/.bashrc[root@www ~]# ll catfile ~/.bashrc-rw-r--r-- 1 root root 194 Sep 26 13:36 /root/.bashrc-rw-r--r-- 1 root root 194 Feb 6 18:29 catfile# 注意看,这两个文件的大小会一模一样!几乎像是使用 cp 来复制一般!
范例三:用 "eof" 代表输入结束[root@www ~]# cat > catfile << "eof"> This is a test.> OK now stop> eof <==输入这关键词,立刻就结束而不需要输入 [ctrl]+d
[root@www ~]# cat catfileThis is a test.OK now stop <==只有这两行,不会存在关键词那一行!
范例二,注解:
首先 cat 命令后不加参数是将我们屏幕输入信息后在屏幕显示.然后我们利用重导向将标准输入用 ~/.bashrc 代替,标准输出重导向到 catfile 这个文件中,即如图所示:
这个管线命令『 | 』把墙面一个命令的正确输出信息(即 standard output ,但对 standard error 并没有直接处理的能力) 作为输入信息传递给后面一个命令,如下图所示
注意:
- 管线命令仅会处理 standard output,对于 standard error output 会予以忽略
- 管线命令必须要能够接受来自前一个命令的数据成为 standard input 继续处理才行
[变量操作命名][变量内容操作][通配符与特殊符号]
变量操作命令:[echo][unset][env][set][export][read][declare]
- 变量与变量内容以一个等号『=』来连结『myname=VBird』
- 等号两边不能直接接空格符(『myname = VBird』或『myname=VBird Tsai』为错误范例)
- 变量名称只能是英文字母与数字,不能以数字开头(『2myname=VBird』为错误范例)
- 变量内容若有空格符可使用双引号『"』或单引号『'』将变量内容结合起来,区别如下
- 双引号内的特殊字符如 $ 等,可以保有原本的特性(『var="lang is $LANG"』则『echo $var』可得『lang is en_US』)
- 单引号内的特殊字符则仅为一般字符 (纯文本)(『var='lang is $LANG'』则『echo $var』可得『lang is $LANG』)
- 可用转义字符『 』将特殊符号(如 [Enter], $, , 空格符, '等)变成一般字符
- 通常大写字符为系统默认变量,自行配置变量可以使用小写字符,方便判断 (纯粹依照使用者兴趣与嗜好)
[root@www ~]# echo $variable
[root@www ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
[root@www ~]# echo ${PATH}
[root@www ~]# unset name
范例一:列出目前的 shell 环境下的所有环境变量与其内容.[root@www ~]# envHOSTNAME=www.vbird.tsai <== 这部主机的主机名TERM=xterm <== 这个终端机使用的环境是什么类型SHELL=/bin/bash <== 目前这个环境下,使用的 Shell 是哪一个程序?HISTSIZE=1000 <== 『记录命令的笔数』在 CentOS 默认可记录 1000 笔USER=root <== 使用者的名称啊!LS_COLORS=no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=00;32:*.cmd=00;32:*.exe=00;32:*.com=00;32:*.btm=00;32:*.bat=00;32:*.sh=00;32:*.csh=00;32:*.tar=00;31:*.tgz=00;31:*.arj=00;31:*.taz=00;31:*.lzh=00;31:*.zip=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.bz=00;31:*.tz=00;31:*.rpm=00;31:*.cpio=00;31:*.jpg=00;35:*.gif=00;35:*.bmp=00;35:*.xbm=00;35:*.xpm=00;35:*.png=00;35:*.tif=00;35: <== 一些颜色显示MAIL=/var/spool/mail/root <== 这个用户所取用的 mailbox 位置PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin:/root/bin <== 不再多讲啊!是运行文件命令搜寻路径INPUTRC=/etc/inputrc <== 与键盘按键功能有关.可以配置特殊按键!PWD=/root <== 目前用户所在的工作目录 (利用 pwd 取出!)LANG=en_US <== 这个与语系有关,底下会再介绍!HOME=/root <== 这个用户的家目录啊!_=/bin/env <== 上一次使用的命令的
[root@www ~]# setBASH=/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=$'
' <== 默认的分隔符LINES=35 <== 目前的终端机下的最大行数MACHTYPE=i686-redhat-linux-gnu <== 安装的机器类型MAILCHECK=60 <== 与邮件有关.每 60 秒去扫瞄一次信箱有无新信!OLDPWD=/home <== 上个工作目录.我们可以用 cd - 来取用这个变量.OSTYPE=linux-gnu <== 操作系统的类型!PPID=20025 <== 父程序的 PID (会在后续章节才介绍)PS1='[럹W]$ ' <== PS1 就厉害了.这个是命令提示字符,也就是我们常见的 [root@www ~]# 或 [dmtsai ~]$ 的配置值啦!可以更动的!PS2='> ' <== 如果你使用跳脱符号 () 第二行以后的提示字符也name=VBird <== 刚刚配置的自定义变量也可以被列出来喔!$ <== 目前这个 shell 所使用的 PID? <== 刚刚运行完命令的回传值.
- $:(关于本 shell 的 PID)
- ?:(关于上个运行命令的回传值)
- PS1:(提示字符的配置)
[Enter] 按键去运行某个命令后,最后要再次出现提示字符时, 就会主动去读取这个变量值了.上头 PS1 内显示的是一些特殊符号,这些特殊符号可以显示不同的信息, 每个 distributions 的 bash 默认的 PS1 变量内容可能有些许的差异,PS1 的相关说明,其中的一些符号意义.
- d :可显示出『星期 月 日』的日期格式,如:"Mon Feb 2"
- H :完整的主机名.举例来说,鸟哥的练习机为『www.vbird.tsai』
- h :仅取主机名在第一个小数点之前的名字,如鸟哥主机则为『www』后面省略
- :显示时间,为 24 小时格式的『HH:MM:SS』
- T :显示时间,为 12 小时格式的『HH:MM:SS』
- A :显示时间,为 24 小时格式的『HH:MM』
- @ :显示时间,为 12 小时格式的『am/pm』样式
- ゆ使用者的账号名称,如『root』;
- v :BASH 的版本信息,如鸟哥的测试主板本为 3.2.25(1),仅取『3.2』显示
- w :完整的工作目录名称,由根目录写起的目录名称.但家目录会以 ~ 取代;
- W :利用 basename 函数取得工作目录名称,所以仅会列出最后一个目录名.
- # :下达的第几个命令.
- $ :提示字符,如果是 root 时,提示字符为 # ,否则就是 $
[root@www ~]# export [var]选项与参数:var 要转换为环境变量的自定义变量(若没有这个选项列出全部环境变量)
环境变量与自定义变量区别:环境变量会被子进程继承而自定义变量则不会如下图所示
[root@www ~]# read [-pt] variable选项与参数:-p :后面可以接提示字符!-t :后面可以接等待的『秒数!』这个比较有趣~不会一直等待使用者啦!
范例一:让用户由键盘输入一内容,将该内容变成名为 atest 的变量[root@www ~]# read atestThis is a test <==此时光标会等待你输入!请输入左侧文字看看[root@www ~]# echo $atestThis is a test <==你刚刚输入的数据已经变成一个变量内容!
范例二:提示使用者 30 秒内输入自己的大名,将该输入字符串作为名为 named 的变量内容[root@www ~]# read -p "Please keyin your name: " -t 30 namedPlease keyin your name: VBird Tsai <==注意看,会有提示字符喔![root@www ~]# echo $namedVBird Tsai <==输入的数据又变成一个变量的内容了!
[root@www ~]# declare [-aixr] variable选项与参数:-a :将后面名为 variable 的变量定义成为数组 (array) 类型-i :将后面名为 variable 的变量定义成为整数数字 (integer) 类型-x :用法与 export 一样,就是将后面的 variable 变成环境变量;-r :将变量配置成为 readonly 类型,该变量不可被更改内容,也不能 unset
范例一:让变量 sum 进行 100+300+50 的加总结果[root@www ~]# sum=100+300+50[root@www ~]# echo $sum100+300+50 <==咦!怎么没有帮我计算加总?因为这是文字型态的变量属性啊![root@www ~]# declare -i sum=100+300+50[root@www ~]# echo $sum450 <==瞭乎??
情况1:
范例一:先让小写的 path 自定义变量配置的与 PATH 内容相同[root@www ~]# path=${PATH}[root@www ~]# echo $path/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
<==这两行其实是同一行啦!
范例二:假设我不喜欢 kerberos,所以要将前两个目录删除掉,如何显示?[root@www ~]# echo ${path#/*kerberos/bin:}/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
上面这个范例很有趣的!他的重点可以用底下这张表格来说明:
${variable#/*kerberos/bin:
} 上面的特殊字体部分是关键词!用在这种删除模式所必须存在的${
variable#/*kerberos/bin:}
这就是原本的变量名称,以上面范例二来说,这里就填写 path 这个『变量名称』啦!${variable
#/*kerberos/bin:}
这是重点!代表『从变量内容的最前面开始向右删除』,且仅删除最短的那个${variable#
/*kerberos/bin:}
代表要被删除的部分,由于 # 代表由前面开始删除,所以这里便由开始的 / 写起.需要注意的是,我们还可以透过通配符 * 来取代 0 到无穷多个任意字符
以上面范例二的结果来看, path 这个变量被删除的内容如下所示:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin <==这两行其实是同一行啦!
情况2
范例三:我想要删除前面所有的目录,仅保留最后一个目录[root@www ~]# echo ${path#/*:}/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin <==这两行其实是同一行啦!#
由于一个 # 仅删除掉最短的那个,因此他删除的情况可以用底下的删除线来看:#
/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:#
/usr/sbin:/usr/bin:/root/bin <==这两行其实是同一行啦!
[root@www ~]# echo ${path##/*:}/root/bin# 嘿!多加了一个 # 变成 ## 之后,他变成『删除掉最长的那个数据』!亦即是:# /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:# /usr/sbin:/usr/bin:/root/bin
范例四:我想要删除最后面那个目录,亦即从 : 到 bin 为止的字符串[root@www ~]# echo ${path%:*bin}/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin <==注意啊!最后面一个目录不见去!# 这个 % 符号代表由最后面开始向前删除!所以上面得到的结果其实是来自如下:# /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:# /usr/sbin:/usr/bin:/root/bin <==这两行其实是同一行啦!
范例五:那如果我只想要保留第一个目录呢?[root@www ~]# echo ${path%%:*bin}/usr/kerberos/sbin# 同样的, %% 代表的则是最长的符合字符串,所以结果其实是来自如下:# /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:# /usr/sbin:/usr/bin:/root/bin <==这两行其实是同一行啦!
变量配置方式 |
说明 |
${变量#关键词}${变量##关键词} |
若变量内容从头开始的数据符合『关键词』,则将符合的最短数据删除若变量内容从头开始的数据符合『关键词』,则将符合的最长数据删除 |
${变量%关键词}${变量%%关键词} |
若变量内容从尾向前的数据符合『关键词』,则将符合的最短数据删除若变量内容从尾向前的数据符合『关键词』,则将符合的最长数据删除 |
${变量/旧字符串/新字符串}${变量//旧字符串/新字符串} |
若变量内容符合『旧字符串』则『第一个旧字符串会被新字符串取代』若变量内容符合『旧字符串』则『全部的旧字符串会被新字符串取代』 |
范例一:测试一下是否存在 username 这个变量,若不存在则给予 username 内容为 root[root@www ~]# echo $username <==由于出现空白,所以 username 可能不存在,也可能是空字符串[root@www ~]# username=${username-root}[root@www ~]# echo $usernameroot <==因为 username 没有配置,所以主动给予名为 root 的内容.[root@www ~]# username="vbird tsai" <==主动配置 username 的内容[root@www ~]# username=${username-root}[root@www ~]# echo $usernamevbird tsai <==因为 username 已经配置了,所以使用旧有的配置而不以 root 取代
在上面的范例中,重点在于减号『 - 』后面接的关键词!基本上你可以这样理解:
new_var=${old_var-content}
新的变量,主要用来取代旧变量.新旧变量名称其实常常是一样的
new_var=${old_var-content}
这是本范例中的关键词部分!必须要存在的哩!
new_var=${old_var-content}
旧的变量,被测试的项目!new_var=${old_var-content}
变量的『内容』,在本范例中,这个部分是在『给予未配置变量的内容』
其他规则可以参考下表
符号 |
意义 |
* |
代表『 0 个到无穷多个』任意字符 |
? |
代表『一定有一个』任意字符 |
[ ] |
同样代表『一定有一个在括号内』的字符(非任意字符).例如 [abcd] 代表『一定有一个字符, 可能是 a, b, c, d 这四个任何一个』 |
[ - ] |
若有减号在中括号内时,代表『在编码顺序内的所有字符』.例如 [0-9] 代表 0 到 9 之间的所有数字,因为数字的语系编码是连续的! |
[^ ] |
若中括号内的第一个字符为指数符号 (^) ,那表示『反向选择』,例如 [^abc] 代表 一定有一个字符,只要是非 a, b, c 的其他字符就接受的意思. |
符号 |
内容 |
# |
批注符号:这个最常被使用在 script 当中,视为说明!在后的数据均不运行 |
|
跳脱符号:将『特殊字符或通配符』还原成一般字符 |
| |
管线 (pipe):分隔两个管线命令的界定(后两节介绍); |
; |
连续命令下达分隔符:连续性命令的界定 (注意!与管线命令并不相同) |
~ |
用户的家目录 |
$ |
取用变量前导符:亦即是变量之前需要加的变量取代值 |
& |
工作控制 (job control):将命令变成背景下工作 |
! |
逻辑运算意义上的『非』 not 的意思! |
/ |
目录符号:路径分隔的符号 |
>, >> |
数据流重导向:输出导向,分别是『取代』与『累加』 |
<, << |
数据流重导向:输入导向 (这两个留待下节介绍) |
' ' |
单引号,不具有变量置换的功能 |
" " |
具有变量置换的功能! |
` ` |
两个『 ` 』中间为可以先运行的命令,亦可使用 $( ) |
( ) |
在中间为子 shell 的起始与结束 |
{ } |
在中间为命令区块的组合! |