《Linux_Shell脚本攻略.第3版》读书笔记

第 1 章 小试牛刀

在终端中显示输出

$表示普通用户#表示管理员用户root。使用sudo 执行命令的效果和root一样。
shell脚本通常以shebang起始:
#!/bin/bash
shebang是一个文本行,其中#!位于解释器路径之前。/bin/bash是Bash的解释器命令路径。bash将以#符号开头的行视为注释。脚本中只有第一行可以使用shebang来定义解释该脚本所用的解释器。脚本的执行方式有两种。
(1) 将脚本名作为命令行参数:

bash myScript.sh

如果将脚本作为bash的命令行参数来运行,那么就用不着使用shebang了
(2) 授予脚本执行权限,将其变为可执行文件:

chmod 755 myScript.sh
./myScript.sh.

使用chmod命令赋予脚本可执行权限:该命令使得所有用户可以按照下列方式执行该脚本:

$ chmod a+x sample.sh
$ ./sample.sh 
#./表示当前目录
&&
$ /home/path/sample.sh #使用脚本的完整路径
$ /bin/bash sample.sh

内核会读取脚本的首行并注意到shebang为#!/bin/bash。它会识别出/bin/bash并执行该当启动一个交互式shell时,它会执行一组命令来初始化提示文本、颜色等设置。这组命令来自用户主目录中的脚本文件~/.bashrc( 对于登录shell则是~/.bash_profile)。Bash shell还维护了一个历史记录文件``~/.bash_history,用于保存用户运行过的命令。

~表示主目录,它通常是/home/user,如果是root用户,则为/root。使用GNOME或KDE这类显示管理器登录后并不会读取.profile或.bash_profile(绝大部分情况下不会),而使用ssh登录远程系统时则会读取.profileshell使用分号或换行符来分隔单个命令或命令序列。比如:

$ cmd1 ; cmd2
#这等同于:
$ cmd1
$ cmd2
# sample.sh - echoes "hello world"
echo "hello world"

echo是用于终端打印的最基本命令。
默认情况下,echo在每次调用后会添加一个换行符:

$ echo "Welcome to Bash"
Welcome to Bash
#不使用双引号也可以得到同样的输出结果:
$ echo Welcome to Bash
Welcome to Bash
#实现相同效果的另一种方式是使用单引号:
$ echo 'text in quotes'

这些方法看起来相似,但各有特定的用途及副作用。双引号允许shell解释字符串中出现的特殊字符。单引号不会对其做任何解释
shell不执行脚本中的任何注释部分。

$ echo "cannot include exclamation -! within double quotes"
#命令输出如下:
bash: !: event not found error

如果需要打印像!这样的特殊字符,那就不要将其放入双引号中,而是使用单引号,或是在特殊字符之前加上一个反斜线(\)

[yibuguwo@liruilong home]$ echo Hello world !
Hello world !
[yibuguwo@liruilong home]$ echo "Hello world !"
bash: !": event not found
[yibuguwo@liruilong home]$ echo 'Hello world !'
Hello world !
[yibuguwo@liruilong home]$ echo "Hello world \!"
Hello world \!
[yibuguwo@liruilong home]$ echo "Hello world \!"
Hello world \!
[yibuguwo@liruilong home]$ 

如果不使用引号,我们无法在echo中使用分号,因为分号在Bash shell中用作命令间的分隔符:
echo hello; hello

printf命令接受引用文本或由空格分隔的参数。我们可以在printf中使用格式化字符串来指定字符串的宽度、左右对齐方式等。默认情况下,printf并不会自动添加换行符,我们必须在需要的时候手动指定,比如在下面的脚本中:

#!/bin/bash
#文件名: printf.sh
printf "Hello world"
printf "%-5s %-10s %-4s\n" No Name Mark
printf "%-5s %-10s %-4.2f\n" 1 Sarath 80.3456
printf "%-5s %-10s %-4.2f\n" 2 James 90.9989
printf "%-5s %-10s %-4.2f\n" 3 Jeff 77.564
  • %s、%c、%d和%f都是格式替换符(format substitution character),它们定义了该如何打印后
    续参数。%-5s指明了一个格式为左对齐且宽度为5的字符串替换(-表示左对齐)。如果不指明-,
    字符串就采用右对齐形式。宽度指定了保留给某个字符串的字符数量。对Name而言,其保留宽
    度是10。因此,任何Name字段的内容都会被显示在10字符宽的保留区域内,如果内容不足10个
    字符,余下的则以空格填充。
  • 对于浮点数,可以使用其他参数对小数部分进行舍入(round off)。
  • 对于Mark字段,我们将其格式化为%-4.2f,其中.2指定保留两位小数。注意,在每行的格
    式字符串后都有一个换行符(\n)。
  1. 在echo中转义换行符
    默认情况下,echo会在输出文本的尾部追加一个换行符。可以使用选项-n来禁止这种行为。
    echo同样接受双包含转义序列的双引号字符串作为参数。在使用转义序列时,需要使用echo -e"包含转义序列的字符串"这种形式。例如:
echo -e "1\t2\t3"
1 2 3
  1. 打印彩色输出
    脚本可以使用转义序列在终端中生成彩色文本。
    文本颜色是由对应的色彩码来描述的。其中包括:重置=0,黑色=30,红色=31,绿色=32,
    黄色=33,蓝色=34,洋红=35,青色=36,白色=37。
    要打印彩色文本,可输入如下命令:
echo -e "\e[1;31m This is red text \e[0m"

其中\e[1;31m是一个转义字符串,可以将颜色设为红色,\e[0m将颜色重新置回。只需要将31替换成想要的色彩码就可以了。
对于彩色背景,经常使用的颜色码是:重置=0,黑色=40,红色=41,绿色=42,黄色=43,
蓝色=44,洋红=45,青色=46,白色=47。

扫描二维码关注公众号,回复: 12593788 查看本文章

要设置彩色背景的话,可输入如下命令:

echo -e "\e[1;42m Green Background \e[0m"

这些例子中包含了一些转义序列。可以使用man console_codes来查看相关文档。

使用变量与环境变量

所有的编程语言都利用变量来存放数据,以备随后使用或修改。和编译型语言不同,大多数
脚本语言不要求在创建变量之前声明其类型。用到什么类型就是什么类型。在变量名前面加上一
个美元符号就可以访问到变量的值。shell定义了一些变量,用于保存用到的配置信息,比如可用
的打印机、搜索路径等。这些变量叫作环境变量。
可以使用env或printenv命令查看当前shell
中所定义的全部环境变量:

$> env
PWD=/home/clif/ShellCookBook
HOME=/home/clif
SHELL=/bin/bash

要查看其他进程的环境变量,可以使用如下命令:

cat /proc/$PID/environ

其中,PID是相关进程的进程ID(PID是一个整数)。
假设有一个叫作gedit的应用程序正在运行。我们可以使用pgrep命令获得gedit的进程ID:

$ pgrep gedit
#12501

那么,你就可以执行以下命令来查看与该进程相关的环境变量:

$ cat /proc/12501/environ
GDM_KEYBOARD_LAYOUT=usGNOME_KEYRING_PID=1560USER=slynuxHOME=/home/slynux 

特殊文件/proc/PID/environ是一个包含环境变量以及对应变量值的列表。每一个变量以name=value的形式来描述,彼之间由null字符(\0)分隔。形式上确实不太易读。要想生成一份易读的报表,可以将cat命令的输出通过管道传给tr,将其中的\0替换成\n

$ cat /proc/12501/environ | tr '\0' '\n'

实战演练

可以使用等号操作符为变量赋值:

varName=value

varName是变量名,value是赋给变量的值。如果value不包含任何空白字符(例如空格),那么就不需要将其放入引号中,否则必须使用单引号或双引号。注意,var = value不同于var=value。把var=value写成var = value是一个常见的错误。两边没有空格的等号是赋值操作符,加上空格的等号表示的是等量关系测试。在变量名之前加上美元符号($)就可以访问变量的内容。

var="value" #将"value"赋给变量var
echo $var
也可以这样写:
echo ${var}
输出如下:
value

我们可以在printf、echo或其他命令的双引号中引用变量值:

#!/bin/bash
#文件名:variables.sh
fruit=apple
count=5
echo "We have $count ${fruit}(s)"
#输出如下:
We have 5 apple(s)

因为shell使用空白字符来分隔单词,所以我们需要加上一对花括号来告诉shell这里的变量名是fruit,而不是fruit(s)。环境变量是从父进程中继承而来的变量。例如环境变量HTTP_PROXY,它定义了Internet连接应该使用哪个代理服务器。该环境变量通常被设置成:

HTTP_PROXY=192.168.1.23:3128
export HTTP_PROXY

export命令声明了将由子进程所继承的一个或多个变量
这些变量被导出后,当前shell脚本所执行的任何应用程序都会获得这个变量。shell创建并用到了很多标准环境变量,我们也可以导出自己的环境变量。
例如,PATH变量列出了一系列可供shell搜索特定应用程序的目录。一个典型的PATH变量包
含如下内容:

[yibuguwo@liruilong /]$ su root
Password: 
[root@liruilong /]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64/bin:/usr/tomcat/apache-tomcat-9.0.21/lib:/root/bin
[root@liruilong /]#

各目录路径之间以:分隔。$PATH通常定义在/etc/environment、/etc/profile或~/.bashrc中。如果需要在PATH中添加一条新路径,可以使用如下命令:

export PATH="$PATH:/home/user/bin"
也可以使用
$ PATH="$PATH:/home/user/bin"
$ export PATH
$ echo $PATH
/home/slynux/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr
/games:/home/user/bin

这样,我们就将/home/user/bin添加到了PATH中。另外还有一些众所周知的环境变量:HOME、PWD、USER、UID、SHELL等

使用单引号时,变量不会被扩展(expand),仍依照原样显示。这意味着$ echo ‘$ var’ 会显示$ var。但如果变量 $ var已经定义过,那么$ echo " $var"会显示出该变量的值;

  • 获得字符串的长度可以用下面的方法获得变量值的长度:length就是字符串所包含的字符数。
$ var=12345678901234567890
$ echo ${#var}
20
  • 识别当前所使用的shell,可以通过环境变量SHELL获知当前使用的是哪种shell:
echo $SHELL
echo $0
$ echo $SHELL
  • 检查是否为超级用户
    环境变量UID中保存的是用户ID。它可以用于检查当前脚本是以root用户还是以普通用户的
    身份运行的。例如:
If [ $UID -ne 0 ]; then
 echo Non root user. Please run as root.
else
 echo Root user
fi

注意,[实际上是一个命令,必须将其与剩余的字符串用空格隔开。上面的脚本也可以写成:

If test $UID -ne 0:1
 then
  echo Non root user. Please run as root.
 else 
  echo Root user
fi
  • 修改Bash的提示字符串(username@hostname:~ $ )
    当我们打开终端或是运行shell时,会看到类似于user@hostname:/home/$的提示字符串。不同的GNU/Linux发布版中的提示字符串及颜色各不相同。我们可以利用PS1环境变量来定义主提示字符串。默认的提示字符串是在文件~/.bashrc中的某一行设置的。
    • 查看设置变量PS1的那一行:
$ cat ~/.bashrc | grep PS1
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
  • 如果要修改提示字符串,可以输入:
slynux@localhost: ~$ PS1="PROMPT>" #提示字符串已经改变
PROMPT> Type commands here.
  • 我们可以利用类似于\e[1;31的特定转义序列来设置彩色的提示字符串(参考1.2节的内容)。还有一些特殊的字符可以扩展成系统参数。例如:\u可以扩展为用户名,\h可以扩展为主机名,而\w可以扩展为当前工作目录。

使用函数添加环境变量

环境变量通常保存了可用于搜索可执行文件、库文件等的路径列表。例如 P A T H 和 PATH和 PATHLD_LIBRARY_PATH,它们通常看起来像这样:

PATH=/usr/bin; /bin
LD_LIBRARY_PATH=/usr/lib; /lib

这意味着只要shell执行应用程序(二进制文件或脚本)时,它就会首先查找/usr/bin,然后查找/bin。当你使用源代码构建并安装程序时,通常需要为新的可执行文件和库文件添加特定的路径。假设我们要将myapp安装到/opt/myapp,它的二进制文件在/opt/myapp/bin目录中,库文件在/opt/myapp /lib目录中。

这个例子展示了如何将新的路径添加到环境变量的起始部分。第一个例子利用我们目前所讲过的知识来实现,第二个例子创建了一个函数来简化修改操作。本章随后会讲到函数。

export PATH=/opt/myapp/bin:$PATH
export LD_LIBRARY_PATH=/opt/myapp/lib; $LD_LIBRARY_PATH

PATH和LD_LIBRARY_PATH现在看起来应该像这样:

PATH=/opt/myapp/bin:/usr/bin:/bin
LD_LIBRARY_PATH=/opt/myapp/lib:/usr/lib; /lib

我们可以在.bashrc文件中定义如下函数,简化路径添加操作

prepend() {
    
     [ -d "$2" ] && eval $1=\"$2':'\$$1\" && export $1; }

该函数用法如下

prepend PATH /opt/myapp/bin
prepend LD_LIBRARY_PATH /opt/myapp/lib

函数prepend()首先确认该函数第二个参数所指定的目录是否存在。如果存在,eval表达式将第一个参数所指定的变量值设置成第二个参数的值加上:(路径分隔符),随后再跟上第一个参数的原始值。在进行添加时,如果变量为空,则会在末尾留下一个:要解决这个问题,可以对该函数再做一些修改:

prepend() {
    
     [ -d "$2" ] && eval $1=\"$2\$\{
    
    $1:+':'\$$1\}\" && export $1 ; }

在这个函数中,我们引入了一种shell参数扩展的形式:${parameter:+expression}如果parameter有值且不为空,则使用expression的值。通过这次修改,在向环境变量中添加新路径时,当且仅当旧值存在,才会增加:。

使用 shell 进行数学运算

Bash shell使用let、(( ))和[]执行基本的算术操作。工具expr和bc可以用来执行高级操作。

(1) 可以像为变量分配字符串值那样为其分配数值。这些值会被相应的操作符视为数字。

#!/bin/bash
no1=4;
no2=5; 

(2) let命令可以直接执行基本的算术操作。当使用let时,变量名之前不需要再添加$,例如:

let result=no1+no2
echo $result

let命令的其他用法如下:

#自加操作
$ let no1++
#自减操作
$ let no1--
#简写形式
let no+=6
let no-=6

操作符[]的使用方法和let命令一样:

result=$[ no1 + no2 ]
#在[]中也可以使用$前缀,例如:
result=$[ $no1 + 5 ]
#也可以使用操作符(())。出现在(())中的变量名之前需要加上$:
result=$(( no1 + 50 ))
#expr同样可以用于基本算术操作:
result=`expr 3 + 4`
result=$(expr $no1 + 5)

以上这些方法不支持浮点数,只能用于整数运算。
(3) bc是一个用于数学运算的高级实用工具

echo "4 * 0.56" | bc
#2.24
no=54;
result=`echo "$no * 1.5" | bc`
echo $result
#81.0 

bc可以接受操作控制前缀。这些前缀之间使用分号分隔。
 设定小数精度。在下面的例子中,参数scale=2将小数位个数设置为2。因此,bc将会输出包含两个小数位的数值:

echo "scale=2;22/7" | bc
#3.14

 进制转换。用bc可以将一种进制系统转换为另一种。来看看下面的代码是如何在十进制与二进制之间相互转换的:

#!/bin/bash
#3用途:数字转换
no=100
echo "obase=2;$no" | bc
1100100
no=1100100
echo "obase=10;ibase=2;$no" | bc
100
#计算平方以及平方根。
echo "sqrt(100)" | bc #Square root
echo "10^10" | bc #Square
玩转文件描述符与重定向

文件描述符是与输入和输出流相关联的整数。最广为人知的文件描述符是stdin、stdout和stderr。我们可以将某个文件描述符的内容重定向到另一个文件描述符中。

在编写脚本的时候会频繁用到标准输入(stdin)、标准输出(stdout)和标准错误(stderr)。脚本可以使用大于号将输出重定向到文件中。命令产生的文本可能是正常输出,也可能是错误信息。默认情况下,正常输出(stdout)和错误信息(stderr)都会显示在屏幕上。我们可以分别为其指定特定的文件描述符来区分两者。

文件描述符是与某个打开的文件或数据流相关联的整数。文件描述符0、1以及2是系统预留的。

  •  0 —— stdin (标准输入)。
  •  1 —— stdout(标准输出)。
  •  2 —— stderr(标准错误)。
    (1) 使用大于号将文本保存到文件中:
$ echo "This is a sample text 1" > temp.txt

该命令会将输出的文本保存在temp.txt中。如果temp.txt已经存在,大于号会清空该文件中先前的内容
(2) 使用双大于号将文本追加到文件中:

$ echo "This is sample text 2" >> temp.txt

(3) 使用cat查看文件内容:

$ cat temp.txt
This is sample text 1
This is sample text 2

接着来看看如何重定向stderr。当命令产生错误信息时,该信息会被输出到stderr流。考虑下面的例子:

$ ls +
ls: cannot access +: No such file or directory

这里,+是一个非法参数,因此会返回错误信息。成功和不成功的命令
当一个命令发生错误并退回时,它会返回一个非0的退出状态;而当命令成功完成后,它会返回为0的退出状态。退出状态可以从特殊变量$?中获得(在命令结束之后立刻运行echo $?,就可以打印出退出状态)。

在下面的命令中,我们使用2>(数字2以及大于号)将stderr重定向到out.txt:

$ ls + 2> out.txt #没有问题
#你可以将stderr和stdout分别重定向到不同的文件中:
$ cmd 2>stderr.txt 1>stdout.txt
#下面这种更好的方法能够将stderr转换成stdout,使得stderr和stdout都被重定向到同一个文件中:
$ cmd 2>&1 alloutput.txt
#或者这样
$ cmd &> output.txt

如果你不想看到或保存错误信息,那么可以将stderr的输出重定向到/dev/null,保证一切都会被清除得干干净净。假设我们有3个文件,分别是a1、a2、a3。但是普通用户对文件a1没有“读写执行”权限。如果需要打印文件名以a起始的所有文件的内容,可以使用cat命令。来设置
一些测试文件:

$ echo A1 > a1
$ echo A2 > a2
$ echo A3 > a3
$ chmod 000 a1 #清除所有权限
#使用通配符(a*)显示这些文件内容的话,系统会显示出错信息,因为文件a1没有可读权限:
$ cat a*
cat: a1: Permission denied
A2
A3

其中,cat: a1: Permission denied属于stderr信息。我们可以将其重定向到一个文件中,同时将stdout信息发送到终端。

$ cat a* 2> err.txt # stderr被重定向到err.txt
A2
A3
$ cat err.txt
cat: a1: Permission denied

我们在处理一些命令输出的同时还想将其保存下来,以备后用。stdout作为单数据流(single stream),可以被重定向到文件或通过管道传入其他程序,但是无法两者兼得。
有一种方法既可以将数据重定向到文件,还可以提供一份重定向数据的副本作为管道中后续命令的stdin。tee命令从stdin中读取,然后将输入数据重定向到stdout以及一个或多个文件中。

command | tee FILE1 FILE2 | otherCommand

在下面的代码中,tee命令接收到来自stdin的数据。它将stdout的一份副本写入文件out.txt,同时将另一份副本作为后续命令的stdin。命令cat -n为从stdin中接收到的每一行数据前加上行号并将其写入stdout:

$ cat a* | tee out.txt | cat -n
cat: a1: Permission denied
 1 A2
 2 A3 
#使用cat查看out.txt的内容:
$ cat out.txt
A2
A3

注意,cat: a1: Permission denied 并没有在文件内容中出现,因为
这些信息被发送到了stderr,而tee只能从stdin中读取。
默认情况下,tee命令会将文件覆盖,但它提供了一个-a选项,可用于追加内容。

$ cat a* | tee -a out.txt | cat –n

带有参数的命令可以写成:command FILE1 FILE2 …,或者就简单地使用command FILE。
要发送输入内容的两份副本给stdout,使用-作为命令的文件名参数即可:

$ cmd1 | cmd2 | cmd -
例如:
$ echo who is this | tee -
who is this
who is this

也可以将/dev/stdin作为输出文件名来代替stdin。类似地,使用/dev/stderr代表标准错误,/dev/stdout代表标准输出。这些特殊的设备文件分别对应stdin、stderr和stdout。

重定向操作符(>和>>)可以将输出发送到文件中,而不是终端。>和>>略有差异。 前者会先清空文件,然后再写入内容,而后者会将内容追加到现有文件的尾部默认情况下,重定向操作针对的是标准输出。如果想使用特定的文件描述符,你必须将描述符编号置于操作符之前。

等同于1>;对于>>来说,情况也类似(即>>等同于1>>)。
处理错误时,来自stderr的输出被倾倒入文件/dev/null中。./dev/null是一个特殊的设备文件,它会丢弃接收到的任何数据。null设备通常也被称为黑洞,因为凡是进入其中的数据都将一去不返。
从stdin读取输入的命令能以多种方式接收数据。可以用cat和管道来指定我们自己的文件

$ cat file | cmd
$ cmd1 | cmd2
  1. 将文件重定向到命令
    借助小于号(<),我们可以像使用stdin那样从文件中读取数据:
    $ cmd < file
  2. 重定向脚本内部的文本块
    可以将脚本中的文本重定向到文件。要想将一条警告信息添加到自动生成的文件顶部,可以
    使用下面的代码:
#!/bin/bash
cat<<EOF>log.txt
This is a generated file. Do not edit. Changes will be overwritten.
EOF
#出现在cat <<EOF>log.txt与下一个EOF行之间的所有文本行都会被当作stdin数据。
$ cat log.txt
This is a generated file. Do not edit. Changes will be overwritten.
  1. 自定义文件描述符
    文件描述符是一种用于访问文件的抽象指示器(abstract indicator)。存取文件离不开被称为“文件描述符”的特殊数字。0、1和2分别是stdin、stdout和stderr预留的描述符编号。

exec命令创建全新的文件描述符。如果你熟悉其他编程语言中的文件操作,那么应该对文件打开模式也不陌生。常用的打开模式有3种。

  • 只读模式。
  • 追加写入模式。
  • 截断写入模式。
  • <操作符可以将文件读入stdin。
  • 操作符用于截断模式的文件写入(数据在目标文件内容被截断之后写入)。

  • 操作符用于追加模式的文件写入(数据被追加到文件的现有内容之后,而且该目标文件中原有的内容不会丢失)。
    文件描述符可以用以上3种模式中的任意一种来创建。
    创建一个用于读取文件的文件描述符:

$ exec 3<input.txt #使用文件描述符3打开并读取文件
我们可以这样使用它:
$ echo this is a test line > input.txt
$ exec 3<input.txt
现在你就可以在命令中使用文件描述符3了。例如:
$ cat<&3
this is a test line

如果要再次读取,我们就不能继续使用文件描述符3了,而是需要用exec重新创建一个新的
文件描述符(可以是4)来从另一个文件中读取或是重新读取上一个文件。

创建一个用于写入(截断模式)的文件描述符:
$ exec 4>output.txt #打开文件进行写入
例如:
$ exec 4>output.txt
$ echo newline >&4
$ cat output.txt
newline
创建一个用于写入(追加模式)的文件描述符:
$ exec 5>>input.txt
例如:
$ exec 5>>input.txt
$ echo appended line >&5
$ cat input.txt
newline
appended line

数组与关联数组

数组允许脚本利用索引将数据集合保存为独立的条目。Bash支持普通数组和关联数组,前者使用整数作为数组索引,后者使用字符串作为数组索引。当数据以数字顺序组织的时候,应该使用普通数组,例如一组连续的迭代。当数据以字符串组织的时候,关联数组就派上用场了,例如主机名称。本节会介绍普通数组和关联数组的用法。

Bash从4.0版本才开始支持关联数组。定义数组的方法有很多种。

(1) 可以在单行中使用数值列表来定义一个数组:
array_var=(test1 test2 test3 test4)
#这些值将会存储在以0为起始索引的连续位置上
另外,还可以将数组定义成一组“索引值”:
array_var[0]="test1"
array_var[1]="test2"
array_var[2]="test3"
array_var[3]="test4"
array_var[4]="test5"
array_var[5]="test6"
(2) 打印出特定索引的数组元素内容:
echo ${array_var[0]}
test1
index=5
echo ${array_var[$index]}
test6
(3) 以列表形式打印出数组中的所有值:
$ echo ${array_var[*]}
test1 test2 test3 test4 test5 test6
也可以这样使用:
$ echo ${array_var[@]}
test1 test2 test3 test4 test5 test6
(4) 打印数组长度(即数组中元素的个数):
$ echo ${#array_var[*]}
6

关联数组从Bash 4.0版本开始被引入。当使用字符串(站点名、用户名、非顺序数字等)作为索引时,关联数组要比数字索引数组更容易使用。

  1. 定义关联数组在关联数组中,我们可以用任意的文本作为数组索引。首先,需要使用声明语句将一个变量定义为关联数组:

别名

$ declare -A ass_array
声明之后,可以用下列两种方法将元素添加到关联数组中。
 使用行内“索引值”列表:
$ ass_array=([index1]=val1 [index2]=val2)
 使用独立的“索引值”进行赋值:
$ ass_array[index1]=val1
$ ass_array'index2]=val2
举个例子,试想如何用关联数组为水果制定价格:
$ declare -A fruits_value
$ fruits_value=([apple]='100 dollars' [orange]='150 dollars')
用下面的方法显示数组内容:
$ echo "Apple costs ${fruits_value[apple]}"
Apple costs 100 dollars
2. 列出数组索引
每一个数组元素都有对应的索引。普通数组和关联数组的索引类型不同。我们可以用下面的
方法获取数组的索引列表:
$ echo ${!array_var[*]}
也可以这样
$ echo ${!array_var[@]}
以先前的fruits_value数组为例,运行如下命令:
$ echo ${!fruits_value[*]}
orange apple
对于普通数组,这个方法同样可行。


使用alias命令创建别名。(1) 创建别名。

```bash
$ alias new_command='command sequence'
下面的命令为apt-get install创建了一个别名:
$ alias install='sudo apt-get install'

为了使别名在所有的shell中都可用,可以将其定义放入~/.bashrc文件中。每当一个新的交互式shell进程生成时,都会执行 ~/.bashrc中的命令。

$ echo 'alias cmd="command seq"' >> ~/.bashrc

(3) 如果需要删除别名,只需将其对应的定义(如果有的话)从~/.bashrc中删除,或者使用unalias命令。也可以使用alias example=,这会取消别名example。

(4) 我们可以创建一个别名rm,它能够删除原始文件,同时在backup目录中保留副本。

alias rm='cp $@ ~/backup && rm $@'

创建别名时,如果已经有同名的别名存在,那么原有的别名设置将被新的设置取代。

如果身份为特权用户,别名也会造成安全问题。为了避免对系统造成危害,你应该将命令转义
对别名进行转义:创建一个和原生命令同名的别名很容易,你不应该以特权用户的身份运行别名化的命令。我们可以转义要使用的命令,忽略当前定义的别名:

$ \command

字符\可以转义命令,从而执行原本的命令。在不可信环境下执行特权命令时,在命令前加上\来忽略可能存在的别名总是一种良好的安全实践。这是因为攻击者可能已经将一些别有用心的命令利用别名伪装成了特权命令,借此来盗取用户输入的重要信息。
2. 列举别名
alias命令可以列出当前定义的所有别名:

$ aliasalias lc='ls -color=auto'
alias ll='ls -l'
alias vi='vim'

编写命令行shell脚本时,总是免不了处理当前终端的相关信息,比如行数、列数、光标位置、遮盖的密码字段等。这则攻略将帮助你学习如何采集并处理终端设置。

tput和stty是两款终端处理工具。

下面是一些tput命令的功能演示。

 获取终端的行数和列数:
tput cols
tput lines
 打印出当前的终端名:
tput longname
 将光标移动到坐标(100,100)处:
tput cup 100 100
 设置终端背景色:
tput setb n
其中,n可以在0到7之间取值。
 设置终端前景色:
tput setf n
其中,n可以在0到7之间取值。
包括常用的color ls在内的一些命令可能会重置前景色和背景色。
 设置文本样式为粗体:
tput bold
 设置下划线的起止:
tput smul
tput rmul
 删除从当前光标位置到行尾的所有内容:
tput ed
 输入密码时,脚本不应该显示输入内容。在下面的例子中,我们将看到如何使用stty来
实现这一需求:
#!/bin/sh
#Filename: password.sh
echo -e "Enter password: "
# 在读取密码前禁止回显
stty -echo
read password
# 重新允许回显
stty echo
echo
echo Password read.

stty命令的选项-echo禁止将输出发送到终端,而选项echo则允许发送输出。

猜你喜欢

转载自blog.csdn.net/sanhewuyang/article/details/109455805