首页 > 系统相关 >shell 知识点补充(1)-提示字符的设定/read/declare / typeset/变量设定功能/别名/万用字符与特殊符号

shell 知识点补充(1)-提示字符的设定/read/declare / typeset/变量设定功能/别名/万用字符与特殊符号

时间:2022-10-11 18:08:54浏览次数:55  
标签:字符 设定 shell 变量 str linux var root 万用

1、PS1:(提示字符的设定)

这个比较有意思,可以定制自己的提示符;

当我们每次按下 [Enter] 按键去执行某个指令后,最后要再次出现提示字符时, 就会主动去读取这个变数值了。

预设的 bash 的 PS1 变量内的特殊符号代表意义:


o \d :代表日期,格式为 Weekday Month Date,例如 "Mon Aug 1"
o \H :完整的主机名称。举例来说,鸟哥的练习机 linux.dmtsai.tw ,那么这个主机名称就是 linux.dmtsai.tw
o \h :仅取主机名称的第一个名字。以上述来讲,就是 linux 而已, .dmtsai.tw 被省略。
o \t :显示时间,为 24 小时格式,如: HH:MM:SS
o \T :显示时间,12 小时的时间格式!
o \A :显示时间,24 小时格式, HH:MM
o \u :目前使用者的账号名称;
o \v :BASH 的版本信息;
o \w :完整的工作目录名称。家目录会以 ~ 取代;
o \W :利用 basename 取得工作目录名称,所以仅会列出最后一个目录名。
o \# :下达的第几个指令。
o \$ :提示字符,如果是 root 时,提示字符为 # ,否则就是 $ 啰~

OK!所以,由预设的 PS1 内容为: '\[\u@\h \W\]\$ ' 就可以了解为何我们的提示字符会是: [root@linux ~]# 了吧!好了,那么假设我想要有类似底下的提示字符:


[root@linux /home/dmtsai 16:50 #12]#


,那个 # 代表第 12 次下达的指令。 那么应该如何设定 PS1 呢?可以这样啊:


[root@linux home]# PS1='[\u@\h \w \A #\#]\$ '


[root@linux /home 17:02 #85]#


# 看到了吗?提示字符变了!变的很有趣吧!其中,那个 #85 比较有趣

2、read

要读取来自键盘输入的变量,就是用 read 这个指令了。这个指令最常被用在 shell script 的撰写当中, 以跟使用者进行对谈。关于 script 的写法,在后面章节介绍,底下先来瞧一瞧 read 的相关语法吧!
[root@linux ~]# read [-pt] variable
参数:
-p :后面可以接提示字符!
-t :后面可以接等待的『秒数!』这个比较有趣~不会一直等待使用者啦!
范例:
范例一:让使用者由键盘输入一内容,将该内容变成 atest 变量
[root@linux ~]# read atest
This is a test
[root@linux ~]# echo $atest
This is a test
范例二:提示使用者 30 秒内输入自己的大名,将该输入字符串做成 named 变量
[root@linux ~]# read -p "Please keyin your name: " -t 30 named
Please keyin your name: VBird Tsai
[root@linux ~]# echo $named
VBird Tsai
read 之后不加任何参数,直接加上变量名称,那么底下就会主动出现一个空白行,等待您输入。 如果加上 -t 后面接秒数之后,例如上面的范例当中,那么 30 秒之内没有任何动作时, 该指令就会自动略过了~如果是加上 -p,就可以增加提示信息了;

实练补充:

作用
从标准输入中读取一行。

语法
read [ -p ][  -r ][ -s ][ -u[ n ] ] [  VariableName?Prompt ]

[ VariableName ... ]

描述
read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量,用 IFS(内部字段分隔符)变量中的字符作为分隔符。VariableName 参数指定 shell 变量的名称,shell 变量获取输入行一个字段的值。由VariableName 参数指定的第一个 shell 变量指定给每一个字段的值,由 VariableName 参数指定的第二个 shell 变量指定给第二个字段的值,以此类推,直到最后一个字段。如果标准输入行的字段比相应的由 VariableName 参数指定的 shell 变量的个数多,把全部余下的字段的值赋给指定的最后的 shell 变量。如果比 shell 变量的个数少,则剩余的 shell 变量被设置为空字符串。

注意: 如果省略了 VariableName 参数,变量 REPLY 用作缺省变量名。
由 read 命令设置的 shell 变量影响当前 shell 执行环境。

标志

-p 用 |& (管道,& 的记号名称)读取由 Korn shell 运行的进程的输出作为输入。

注:-p 标志的文件结束符引起该进程的清除,因此产生另外一个进程。
-r 指定读取命令把一个 \ (反斜杠) 处理为输入行的一部分,而不把它作为一个控制字符。
-s 把输入作为一个命令保存在 Korn shell 的历史记录文件中。
-u [ n ] 读取一位数的文件描述符号码 n 作为输入。文件描述符可以用 ksh exec 内置命令打开。n 的缺省值是 0,表示的是键盘。值 2 表示标准错误。

参数

VariableName?Prompt 指定一个变量的名称和一个要使用的提示符。当 Korn shell 是交互式时,它将把提示符写到标准错误,并执行输入。Prompt 包含多于一个的字,必须用单引号或双引号括起来。
VariableName... 指定一个或多个由空格分隔的变量名。

退出状态
这个命令返回下列出口值:

0 成功完成。
>0 检测到文件结束符或一个错误发生。

示例
下列脚本打印一个文件,这个文件中每行的第一个字段被移动到本行的末尾。

while read -r xx yy
do
         print printf "%s %s/n" $yy $xx
done < InputFile读取一行,把它分成字段,并使用 "Please enter: " 作为提示符,请输入:

read word1?"Please enter:  " word2系统显示:

Please enter:
You enter:
hello world变量 word1 的值应该是 "hello",变量 word2 应该是 "world."

为创建一个共同进程,用 print -p 写到共同进程,并用 read -p 从共同进程中读取输入,请输入:

(read; print "hello $REPLY")
print -p "world"
read-p line变量 line 的值应该是 "hello world."

为把输入行的副本保存为历史文件中的一个命令,请输入:

read -s line < input_file如果输入文件包含 "echo hello world," ,那么在历史记录文件中将会把 "echo hello world" 保存为一个命令。




3、 declare / typeset

declare 或 typeset 是一样的功能,就是在宣告变量的属性。如果使用 declare 后面并没有接任何参数, 那么 bash 就会主动的将所有的变量名称与内容通通叫出来,就好像使用 set 一样啦! 那么 declare 还有什么语法呢?看看先:
[root@linux ~]# declare [-aixr] variable
参数:
-a :将后面的 variable 定义成为数组 (array)
-i :将后面接的 variable 定义成为整数数字 (integer)
-x :用法与 export 一样,就是将后面的 variable 变成环境变量;
-r :将一个 variable 的变量设定成为 readonly ,该变量不可被更改内容,也不能 unset
范例:
范例一:让变量 sum 进行 100+300+50 的加总结果
[root@linux ~]# sum=100+300+50
[root@linux ~]# echo $sum
100+300+50 <==咦!怎么没有帮我计算加总?因为这是文字型态的变量属性啊!
[root@linux ~]# declare -i sum=100+300+50
[root@linux ~]# echo $sum
450 <==瞭乎??
范例二:将 sum 变成环境变量
[root@linux ~]# declare -x sum
范例三:让 sum 变成只读属性,不可更动!
[root@linux ~]# declare -r sum
[root@linux ~]# sum=tesgting
-bash: sum: readonly variable <==老天爷~不能改这个变数了!
declare 也是个很有用的功能~尤其是当我们需要使用到底下的数组功能时, 他也可以帮我们宣告数组的属性喔!不过,老话一句,数组也是在 shell script 比较常用的

4、额外的变量设定功能

刚刚我们提到了两种变量取用的方法,分别是这样:
[root@linux ~]# echo $HOME
[root@linux ~]# echo ${HOME}
那么,在那个 ${variable} 的使用方法中,其实,我们还可以将变量进行一些修订的工作喔! 只要加上一些字符标志,后面再接着使用比对字符串,就能够修改变量的内容了! 我们取底下的例子来说明:在底下的例子中,假设我的变量名称为 vbird ,且内容为 /home/vbird/testing/testing.x.sh。
1. 完整呈现 vbird 这个变量的内容;
[root@linux ~]# vbird="/home/vbird/testing/testing.x.sh"
[root@linux ~]# echo ${vbird}
/home/vbird/testing/testing.x.sh
2. 在 vbird 变量中,从最前面开始比对,若开头为 / ,则删除两个 /
之间的所有数据,亦即 /*/
[root@linux ~]# echo ${vbird##/*/}
testing.x.sh <==删除了 /home/vbird/testing/
[root@linux ~]# echo ${vbird#/*/}
vbird/testing/testing.x.sh <==仅删除 /home/ 而已
# 这两个小例子有趣了~变量名称后面如果接了两个 ## ,表示在 ##
# 后面的字符串取『最长的』那一段;如果仅有一个 # ,表示取『最小的那一段』喔!
3. 承上题,如果是从后面开始,删除 /* 呢?
[root@linux ~]# echo ${vbird%%/*/}
/home/vbird/testing/testing.x.sh <==都没被删除
[root@linux ~]# echo ${vbird%%/*}
<==被删除光了!
[root@linux ~]# echo ${vbird%/*}
/home/vbird/testing <==只删除 /testing.x.sh 部分
# 这个例子当中需要特别注意,那个 % 比对的是『最后面那个字符』的意思,
# 所以啰,第一个方式当然不对~因为 vbird 这个变量的内容最后面是 h 而不是 / 啊!
# 至于 %%/* 则是删除『最长的那个 /* 』,当然就是全部喔!而 %/* 则是最短的那个!
4. 将 vbird 变数中的 testing 取代为 TEST
[root@linux ~]# echo ${vbird/testing/TEST}
/home/vbird/TEST/testing.x.sh
[root@linux ~]# echo ${vbird//testing/TEST}
/home/vbird/TEST/TEST.x.sh
# 如果变量后面接的是 / 时,那么表示后面是进行『取代』的工作~而且仅取代『第一个』
# 但如果是 // ,则表示全部的字符串都取代啊!
这里您稍微留意一下就好了~反正就是变量后面可以接 #, ##, %, %%, /, // , 而他们存在的意义并不相同的啦~ 另外,几个不同的变量内容还可以进行判断呢! 举例来说,目前我需要用到两个变量,分别是 var 与 str , 那我想要针对 str 这个变量内容是否有设定成一个字符串,亦即 "expr" 来决定 var 的内容。 那我可以使用什么方法来进行判断呢?如果您会写 shell script 的话, 直接用 shell script 就好了,如果不会写,那么我们就透过简单的变量判断吧!
Tips: 底下的例子当中,那个 var 与 str 为变量,我们想要针对 str 是否有设定来决定 var 的值喔! 一般来说, str: 代表『str 没设定或为空的字符串时』;至于 str 则仅为『没有该变数』。

变量设定方式          str 没有设定                str 为空字符串       str 已设定非为空字符串
var=${str-expr}          var=expr                            var=                           var=$str
var=${str:-expr}         var=expr                          var=expr                       var=$str
var=${str+expr}         var=expr                          var=expr                       var=expr
var=${str:+expr}        var=expr                          var=                               var=expr
var=${str=expr}         str=expr;var=expr       str 不变 var=                 str 不变 var=$str
var=${str:=expr}        str=expr var=expr          str=expr var=expr         str 不变 var=$str
var=${str?expr}         expr 输出至 stderr          var=                                  var=str
var=${str:?expr}        expr 输出至 stderr           expr 输出至 stderr              var=str

根据上面这张表,我们来进行几个范例的练习
范例一:若 str 这个变量内容存在,则 var 设定为 str ,否则 var 设定为 "newvar"
[root@linux ~]# unset str; var=${str-newvar}
[root@linux ~]# echo var="$var", str="$str"
var=newvar, str= <==因为 str 不存在,所以 var 为 newvar
[root@linux ~]# str="oldvar"; var=${str-newvar}
[root@linux ~]# echo var="$var", str="$str"
var=oldvar, str=oldvar <==因为 str 存在,所以 var 等于 str 的内容
范例二:若 str 不存在,则 var 与 str 均设定为 newvar,否则仅 var 为 newvar
[root@linux ~]# unset str; var=${str=newvar}
[root@linux ~]# echo var="$var", str="$str"
var=newvar, str=newvar <==因为 str 不存在,所以 var/str 均为 newvar
[root@linux ~]# str="oldvar"; var=${str=newvar}
[root@linux ~]# echo var="$var", str="$str"
var=oldvar, str=oldvar <==因为 str 存在,所以 var 等于 str 的内容
范例三:若 str 这个变量存在,则 var 等于 str ,否则输出 "novar"
[root@linux ~]# unset str; var=${str?novar}
-bash: str: novar <==因为 str 不存在,所以输出错误讯息
[root@linux ~]# str="oldvar"; var=${str?novar}
[root@linux ~]# echo var="$var", str="$str"
var=oldvar, str=oldvar <==因为 str 存在,所以 var 等于 str 的内容
# 上面这三个案例都没有提到当 str 有设定,且为空字符串的情况喔!
# 您可以自行测试一下哩!
虽然猛一看,觉得变量没有什么奇特的地方,但是,如果仔细瞧一瞧,嘿!一堆环境变量与系统资源方面的变量, 可是会影响到我们在 bash 里头是否能够顺利作业的呢!例如 PATH 啊、ulimit 之类的~

特殊变量:

$*      这个程序的所有参数   如命令ls -al dir  即代表 -al dir

$?     执行上一个命令的返回值     为0表示执行成功!

$!       执行上一个后台命令的PID

$$      这个程序的PID

$#      这个程序的参数个数   如命令ls -al dir  即代表2个

5、别名

增加别名:

Loong:/home/yee/shell# alias vi="vim"
Loong:/home/yee/shell# lm
bash: lm: command not found
Loong:/home/yee/shell# alias lm="vim"
Loong:/home/yee/shell# lm kkk.txt

取消别名:

Loong:/home/yee/shell# una
unalias  uname    
Loong:/home/yee/shell# unalias lm
Loong:/home/yee/shell# lm
bash: lm: command not found
Loong:/home/yee/shell# 

6、万用字符与特殊符号:


!在 bash 里头还支持一些万用字符喔 (wild card) !多了这些万用字符, 我们利用 bash 处理数据就更方便了!底下我们列出一些常用的万用字符喔:
符号
内容

  • *
  • 万用字符,代表 0 个或多个字符(或数字)
  • ?
  • 万用字符,代表『一定有』一个字母
  • #
  • 批注,这个最常被使用在 script 当中,视为说明!
  • \
  • 跳脱符号,将『特殊字符或万用字符』还原成一般字符
  • |
  • 分隔两个管线命令的界定;
  • ;
  • 连续性命令的界定(注意!与管线命令并不相同)
  • ~
  • 使用者的家目录
  • $
  • 亦即是变量之前需要加的变量取代值
  • &
  • 将指令变成背景下工作
  • !
  • 逻辑运算意义上的『非』 not 的意思!
  • /
  • 路径分隔的符号
  • >, >>
  • 输出导向,分别是『取代』与『累加』
  • '
  • 单引号,不具有变量置换的功能
  • "
  • 具有变量置换的功能!
  • ` `
  • 两个『 ` 』中间为可以先执行的指令!
  • ( )
  • 在中间为子 shell 的起始与结束
  • [ ]
  • 在中间为字符的组合
  • { }
  • 在中间为命令区块的组合!
  • 组合按键
  • 执行结果
  • Ctrl + C
  • 终止目前的命令
  • Ctrl + D
  • 输入结束(EOF),例如邮件结束的时候;
  • Ctrl + M
  • 就是 Enter 啦!
  • Ctrl + S
  • 暂停屏幕的输出
  • Ctrl + Q
  • 恢复屏幕的输出
  • Ctrl + U
  • 在提示字符下,将整列命令删除
  • Ctrl + Z
  • 『暂停』目前的命令

[root@linux ~]# ls test* <==那个 * 代表后面不论接几个字符都予以接受
[root@linux ~]# ls test? <==那个 ? 代表后面『一定』要接『一个』字符
[root@linux ~]# ls test??? <==那个 ??? 代表『一定要接三个』字符!
[root@linux ~]# cp test[1-5] /tmp
# 将 test1, test2, test3, test4, test5 若存在的话,就拷贝到 /tmp
[root@linux ~]# cp test[!1-5] /tmp
# 只要不是 test1, test2, test3, test4, test5 之外的其它 test? ,
# 若存在的话,就拷贝到 /tmp
[root@linux ~]# cd /lib/modules/`uname -r`/kernel/drivers
# 被 ` ` 括起来的内容『会先执行』
上面几个例子相当的有趣!尤其是最后面两个!需要注意的是, [1-5] 里面『代表只有一个字符』但是范围可以由 1-5 ,这样来说的话,那么我们如果允许『只要档名里面含有至少一个大写字符』时,就可以将档案 copy 出来的话,可以这样做:
cp *[A-Z]* /tmp
很有趣吧?!也就是说『 [ ] 谨代表一个字符,而这个字符的定义可以是范围(-), 可以是指定项目,也可以是两者并存。 』举例来说,我想要找出在 /etc/ 底下所有含有数字的档案, 可以这样:
ls -lda /etc/*[0-9]*
但如果我只想要找出含有 3 及 5 的档名的档案呢?就会是这样:
ls -lda /etc/*[35]*
如果是『不想要』某些范围或者是单字呢?就使用 [!] 即可!例如不想要有小写字符为开头的档案:
ls -lda /etc/[!a-z]*
很好玩吧!至于那个 ` 是啥?在一串指令当中, `command` 内的指令会先被执行, 执行完的讯息再回传到外部指令来处理!也就是说:
1. 系统先执行 uname -r 找出输出的结果;
2. 将结果累加在目录上面,来执行 cd 的功能!
很棒吧!!另外,这个 quot (`) 的功能,也可以利用 $() 来取代喔!例如:
cd /lib/modules/$(uname -r)/kernel
这些基本的功能需要特别来了解一下才行


内容摘自:《鸟哥私房菜》



标签:字符,设定,shell,变量,str,linux,var,root,万用
From: https://blog.51cto.com/u_15797945/5747499

相关文章