Linux学习路线之二【The linux command line---shell篇】

前言

恰如我们之前所讲的,shell 在shell 会话中保存着大量信息。这些信息被称为(shell 的) 环境。程序获取环境中的数据(即环境变量)来了解本机的配置。虽然大多数程序用配置文件来存储程序设置,一些程序会根据环境变量来调整他们的行为。知道了这些,我们就可以用环境变量来自定制shell 体验。shell目前又分bash、cshell、tcsh等。此处只介绍bash。

一、常用命令

  • printenv----打印部分或者所有的环境变量
  • set ----设置shell选项
  • export ----导出环境变量,让随后执行的程序知道
  • alias -----创建命令别名
    1. printenv
    执行printenv命令之后,我们应该能得到类似以下内容:
[angel@linux ~]$ printenv | less
KDE_MULTIHEAD=false
SSH_AGENT_PID=7777
HOSTNAME=linux
GPG_AGENT_INFO=/tmp/gpg-PdOt7g/S.gpg-agent:6670:2
SHELL=/bin/bash
TERM=xterm
XDG_MENU_PREFIX=kde-
HISTSIZE=1000
XDG_SESSION_COOKIE=6d7b05c65845c3eef3101b2246bd2b00-12085210990.989705
-1177056199
GTK2_RC_FILES=/etc/gtk-2.0/gtkrc:/home/me/.gtkrc-2.0:/home/me/.kde/sh
are/config/gtkrc-2.0
GTK_RC_FILES=/etc/gtk/gtkrc:/home/me/.gtkrc:/home/me/.kde/share/confi
g/gtkrc
GS_LIB=/home/me/.fonts
WINDOWID=29360136
QTDIR=/usr/lib/qt-3.2
QTINC=/usr/lib/qt-3.2/include
KDE_FULL_SESSION=true
USER=angel
LS_COLORS=no=01:fi=02:di=00;32:ln=00;35:pi=42;33:so=00;33:bd=50;33;01
:cd=40;33;01:or=03;05;37;41:mi=05;05;37;41:ex=00;32:\*.cmd=00;32:\*.exe:

printenv按照特定数值打印变量:

[angel@linux ~]$ printenv USER
angel

2.set、export
设置变量参数:

set ShareFolder = /data/home/share             #bash和csh通用
export PATH=/local/usr/bin:$PATH               #export用于bash脚本里,设置环境变量

3. alias
使用alias 自定义一些简化命令,方便操作:

[angel@linux ~]$ alias
alias l.='ls -d .* --color=tty'
alias ll='ls -l --color=tty'
alias ls='ls --color=tty'
alias vi='vim'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

二、创建执行bash/cshell脚本

2.1 脚本文件格式

为了保持编程传统,我们将创建一个“hello world”程序来说明一个极端简单的脚本。所以让我们启动我们的文本编辑器,然后输入以下脚本,并保存为hello_word.sh格式

#!/bin/bash
# This is our first script.
echo 'Hello World!'

下方是保存为hello_word.csh格式

#!/bin/csh
# This is our first script.
echo 'Hello World!'

2.2 修改脚本权限

下一步我们要做的事情是让我们的脚本可执行。使用chmod 命令,这很容易做到:

[angel@linux ~]$ ls -l 
-rw-r--r-- 1 angel angel 63 2022-01-19 11:10 hello_world.sh
[angel@linux ~]$ chmod 755 hello_world.sh
[angel@linux ~]$ ls -l 
-rwxr-xr-x 1 angel angel 63 2022-01-19 11:12 hello_world.sh

2.3 执行脚本

使用./或者source都可以执行bash或csh脚本:

[angel@linux ~]$ ./hello_world.sh
Hello World!
[angel@linux ~]$ source hello_world.sh
Hello World!

三、流程控制

3.1 if分支结构

1. 语法格式
if条件语句语法格式如下:

if [ commands ]; then
commands
elif [ commands ]; then
commands…
else
commands
fi

Example:

#!/bin/bash
x=10
if [ $x = 10 ]; then
echo "x equals 10."
else
echo "x does not equal 10."
fi

2. 文件表达式
以下表达式被用来计算文件状态:

表达式如果下列条件为真,返回true
file1 -ef file2file1 和file2 拥有相同的索引号(通过硬链接两个文件名指向相同的文件)
file1 -nt file2file1 比file2新
file1 -ot file2file1 比file2早
-d filefile存在并且是一个目录
-e filefile存在
-f filefile存在并且是一个普通文件
-b filefile存在并且是一个块文件
-c filefile存在并且是一个字符文件
-r filefile存在并且可读
-w filefile存在并且可写
-x filefile存在并且可执行
-L filefile存在并且是一个符号链接

引用一个脚本说明这些表达式:

#!/bin/bash
#evaluate the status of a file
FILE=~/.bashrc
if [ -e "$FILE" ]; then
    if [ -f "$FILE" ]; then
    	echo "$FILE is a regular file!!!"
    fi
    if [ -d "$FILE" ]; then
		echo "$FILE is a directory!!!"
	fi
	if [ -r "$FILE" ]; then
		echo "$FILE is readable!!!"
	fi
	if [ -w "$FILE" ]; then
		echo "$FILE is writable!!!"
	fi
	if [ -x "$FILE" ]; then
		echo "$FILE is executable!!!"
	fi
else
	echo "$FILE does not exist"
	exit 1	
fi
exit

对于此脚本有两点需要注意:

  1. 在表达式中参数 F I L E 是 怎 样 被 引 用 的 。 引 号 并 不 是 必 需 的 , 但 这 是 为 了 防 范 空 参 数 。 如 果 FILE 是怎样被引用的。引号并不是必需的,但这是为了防范空参数。如果 FILEFILE 的参数展开是一个空值,就会导致一个错误(操作符将会被解释为非空的字符串而不是操作符)。用引号把参数引起来就确保了操作符之后总是跟随着一个字符串,即使字符串为空。
  2. 注意脚本末尾的exit 命令。这个exit 命令接受一个单独的,可选的参数,其成为脚本的退出状态。当不传递参数时,退出状态默认为零。以这种方式使用exit
    命令,则允许此脚本提示失败。如果$FILE 展开成一个不存在的文件名。这个exit
    命令出现在脚本中的最后一行,是一个当一个脚本“运行到最后”(到达文件末尾),不管怎样,默认情况下它以退出状态零终止。

类似地,通过带有一个整数参数的return 命令,shell 函数可以返回一个退出状态。如果我们打算把上面的脚本转变为一个shell 函数,为了在更大的程序中包含此函数,我们用return语句来代替exit 命令。

3. 字符串表达式
以下表达式被用来计算字符串:
在这里插入图片描述
警告:当与test 一块使用的时候,> 和< 表达式操作符必须用引号引起来(或者是用反斜杠转义)。

#!/bin/bash
# test-string: evaluate the value of a string
ANSWER=hello
if [ -z "$ANSWER" ]; then
	echo "There is no answer." >&2
	exit 1
fi
if [ "$ANSWER" = "yes" ]; then
	echo "The answer is YES."
elif [ "$ANSWER" = "no" ]; then
	echo "The answer is NO."
elif [ "$ANSWER" = "hello" ]; then
	echo "The answer is HELLO."
else
	echo "The answer is UNKNOWN."
fi

在这个脚本中,我们计算常量ANSWER。我们首先确定是否此字符串为空。如果为空,我们就终止脚本,并把退出状态设为1。

4. 整形表达式
下面的表达式用于整数:
在这里插入图片描述
这里是一个演示以上表达式用法的脚本:

#!/bin/bash
#test-Integer: evaluate the value of an integer
INT=-5
if [ -z "$INT" ]; then
	echo "$INT is empty." >&2
	exit 1
fi
if [ $INT -eq 0 ]; then
	echo "INT is zero."
else
	if [ $INT -lt 0 ]; then
		echo "INT is negative."
	fi
	if [ $INT -gt 0 ]; then
		echo "INT is positive."
	fi
fi

此外,可以使用[[ expression ]] 添加的另一个功能是== 操作符支持类型匹配,正如路径名展开所做的那样

string1 =~ regex

if [[ $FILE == foo.* ]]; then
	echo "$FILE matches pattern 'foo.*'"
fi
#or
if [[ $VCS_HOME != "" ]] && [[ -d "${SW_HOME}"]]; then
	export VCS_HOME=$VCS_LOCAL_HOME
fi

除了[[ ]] 复合命令之外,bash 也提供了(( )) 复合命令,其有利于操作整数。

#!/bin/bash
# test-integer2a: evaluate the value of an integer.
INT=-5
if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
	if ((INT == 0)); then
		echo "INT is zero."
	else
		if ((INT < 0)); then
			echo "INT is negative."
		else
			echo "INT is positive."
		fi
		if (( ((INT % 2)) == 0)); then
			echo "INT is even."
		else
			echo "INT is odd."
		fi
	fi
else
	echo "INT is not an integer." >&2
	exit 1
fi

5. 结合表达式
有三个用于test 和[[ ]] 的逻辑操作。它们是AND、OR 和NOT。test 和[[ ]] 使用不同的操作符来表示这些操作:
在这里插入图片描述
bash 支持两种可以执行分支任务的控制操作符。&&(AND)和 ||(OR)操作符作用如同复合命令[[ ]] 中的逻辑操作符。这是语法:

if [[ ${AURA_FW_HOME} != "" ]] && [[ -d "${AURA_FW_HOME}" ]] ; then
  export ZXX_AURA_FW_HOME=${AURA_FW_HOME}
elif [[ ${AURA_HOME} != "" ]] || [[ -d "${AURA_HOME}" ]] ; then
  export ZXX_AURA_FW_HOME=${AURA_HOME}/fw
else
  export ZXX_AURA_FW_HOME=/data/home/aura/fw
fi

3.2 while循环

1.语法格式:

while commands; do commands; done

bash 能够表达相似的想法。比方说我们想要按照顺序从1 到5 显示五个数字。可如下构造一个bash 脚本:

#!/bin/bash
# while-count: display a series of numbers
count=3
while [ $count -le 3 ]; do
echo $count
count=$((count + 1))
done
echo "Finished."

执行结果如下:

[angel@linux ~]$ /usr/bin/bash while.sh
1
2
3
Finished.

例如:

#!/bin/bash
# while-menu: a menu driven system information program
DELAY=3 # Number of seconds to display results
while [[ $REPLY != 0 ]]; do
	clear
	cat <<- _EOF_
		Please Select:
		1. Display System Information
		2. Display Disk Space
		3. Display Home Space Utilization
		0. Quit
	_EOF_
	read -p "Enter selection [0-3] > "
	if [[ $REPLY =~ ^[0-3]$ ]]; then
		if [[ $REPLY == 1 ]]; then
			echo "Hostname: $HOSTNAME"
			uptime
			sleep $DELAY
		fi
		if [[ $REPLY == 2 ]]; then
			df -h
			sleep $DELAY
		fi
		if [[ $REPLY == 3 ]]; then
			if [[ $(id -u) -eq 0 ]]; then
				echo "Home Space Utilization (All Users)"
				du -sh /home/*
			else
				echo "Home Space Utilization ($USER)"
				du -sh $HOME
			fi
			sleep $DELAY
		fi
	else
		echo "Invalid entry."
		sleep $DELAY
	fi
done
echo "Program terminated."

只要REPLY 不等于“0”,循环就会继续,菜单就能显示,从而用户有机会重新选择。每次动作完成之后,会执行一个sleep 命令,所以在清空屏幕和重新显示菜单之前,程序将会停顿几秒钟,为的是能够看到选项输出结果。一旦REPLY 等于“0”,则表示选择了“退出”选项,循环就会终止,程序继续执行done 语句之后的代码。

执行结果如下:
在这里插入图片描述
在这里插入图片描述
2.跳出循环:

break ------- 命令立即终止一个循环,且程序继续执行循环之后的语句。
continue-----命令导致程序跳过循环中剩余的语句,且程序继续执行下一次循环。

这里我们看看采用了break 和continue 两个命令的while-menu 程序版本:

#!/bin/bash
# while-menu: a menu driven system information program
DELAY=3 # Number of seconds to display results
while [[ $REPLY != 0 ]]; do
	clear
	cat <<- _EOF_
		Please Select:
		1. Display System Information
		2. Display Disk Space
		3. Display Home Space Utilization
		0. Quit
	_EOF_
	read -p "Enter selection [0-3] > "
	if [[ $REPLY =~ ^[0-3]$ ]]; then
		if [[ $REPLY == 1 ]]; then
			echo "Hostname: $HOSTNAME"
			uptime
			sleep $DELAY
		fi
		if [[ $REPLY == 2 ]]; then
			df -h
			sleep $DELAY
		fi
		if [[ $REPLY == 3 ]]; then
			if [[ $(id -u) -eq 0 ]]; then
				echo "Home Space Utilization (All Users)"
				du -sh /home/*
			else
				echo "Home Space Utilization ($USER)"
				du -sh $HOME
			fi
			sleep $DELAY
			continue
		fi
		if [[ $REPLY == 0 ]]; then
			break
		fi
	else
		echo "Invalid entry."
		sleep $DELAY
	fi
done
echo "Program terminated."

此脚本,当选择“0” 选项的时候,break 命令被用来退出循环。continue 命令被包含在其它选择动作的末尾,来提高程序执行的效率。通过使用continue 命令,当一个选项确定后,程序会跳过不需执行的其他代码。例如,如果选择了选项“1”,则没有理由去测试其它选项。

3.3 case语句

1.语法规则:

case word in
[pattern [| pattern]…) commands ;;]… esac

修改while循环中例子,替换成case逻辑后会更简单:

#!/bin/bash
clear
echo "
Please Select:
1. Display System Information
2. Display Disk Space
3. Display Home Space Utilization
0 .Quit
"
read -p "Enter selection [0-3] > "
case $REPLY in
	0) echo "Program terminate"
	   exit
	   ;;
	1) echo "Hostname: $HOSTNAME"
		uptime
		;;
	2) df -h
		;;
	3) if [[ $(id -u) -eq 0 ]]; then
			echo "Home Space Utilization (All Users)"
			du -sh /home/*
		else
			echo "Home Space Utilization ($USER)"
			du -sh $HOME
		fi
		;;
	*) echo "Invalid entry" >&2
		exit 1
		;;
esac

执行结果如下:

[angel@linux ~bash_test]$ /usr/bin/bash test.sh
Please Select:
1. Display System Information
2. Display Disk Space
3. Display Home Space Utilization
0 .Quit

Enter selection [0-3] > 1
Hostname: angel
 15:11:28 up 189 days,  3:32,  4 users,  load average: 0.22, 0.09, 0.11
[angel@linux ~bash_test]$

2.匹配模式:
模式以一个“)”为终止符。这里是一些有效的模式。

模式描述
a)若单词为a,则匹配
[[:alpha:]])若单词是一个字母字符,则匹配
???)若单词只有三个字符,则匹配
*.txt)若单词以“*.txt“结尾,则匹配
*)匹配任意单词。把这个模式做为case 命令的最后一个模式,是一个很好的做法,可以捕捉到任意一个与先前模式不匹配的数值;也就是说,捕捉到任何可能的无效值
#!/bin/bash
read -p "enter word > "
case $REPLY in
	[[:alpha:]]) echo "is a single alphabetic character." ;;
	[ABC][0-9])  echo "is A, B, or C followed by a digit." ;;
	???)         echo "is three characters long." ;;
	*.txt)       echo "is a word ending in '.txt'" ;;
	*)           echo "is something else." ;;
esac

3.4 for循环

for 循环不同于while 因为在循环中,它提供了一种处理序列的方式。这在编程时非常有用。因此在bash
脚本中,for 循环是非常流行的构造。实现一个for 循环,很自然的,要用for 命令。在现代版的bash中,有两种可用的for 循环格式。

1.for 传统shell格式
命令语法:

for variable [in words]; do
commands
done

这里的variable是变量的名字,这个变量在循环时会增加,words是一个可选的条目列表其值会按顺序赋值给variable,commands 是在每次循环迭代中要执行的命令。在命令行中for 命令是很有用的。我们可以很容易的说明它是如何工作的:

[angel@linux ~]$ for i in A B C D; do echo $i; done 
#or
[angel@linux ~]$ for i in {A..D}; do echo $i; done
A
B
C
D

for 命令真正强大的功能是我们可以通过许多有趣的方式创建words 列表。或者路径名展开:

[angel@linux ~]$ for i in setup*.txt; do echo $i; done
setup-1.txt
setup-2.txt
setup-names.txt

2.for C语言格式
其中,expression1 用来初始化循环条件,expression2 用来决定循环结束的时间,还有在每次循环
迭代的末尾会执行expression3。

for (( expression1; expression2; expression3 )); do
commands
done

典型应用:

#!/bin/bash
# simple_counter : demo of C style for command
for (( i=0; i<5; i=i+1 )); do
echo $i
done

脚本执行后结果:

[angel@linux ~]$ ./test.sh
0
1
2
3
4

四、读取键盘输入

1.语法格式:

read 从标准输入读取数值,即为读取键盘输入,语法形式如下:

read [options] [variable…]

这里的options 是下面列出的可用选项中的一个或多个,且variable 是用来存储输入数值的一个或多个变量名。如果没有提供变量名,shell 变量REPLY 会包含数据行。基本上,read 会把来自标准输入的字段赋值给具体的变量。如果我们修改我们的整数求值脚本,让其使用read ,它可能看起来像这样:

#!/bin/bash

echo -n "Type the folder name....: "
read newDir

echo -n "new folder is $newDir, (C)ontinue or (E)xit?....(c/e):"
read cont

if [ $cont != "c" ] && [ $cont != "C" ]; then
	exit
fi

mkdir -p ../$newDir
cp -rf makefile *_env.csh *.tcl flist/ cp_compile.sh ../$newDir

我们使用带有-n 选项(其会删除输出结果末尾的换行符)的echo 命令,来显示提示信息,然后使用read 来读入变量int 的数值。运行这个脚本得到以下输出:

[angel@linux ~]$ ./cp.sh
Type the folder name....: test
new folder is test, (C)ontinue or (E)xit?....(c/e):c
[angel@linux ~]$ ls -l ../
drwxr-xr-x  2 angel angel    4096 Jan 19 15:50 test
drwxrwxr-x  2 angel angel    4096 Jan 15  2020 simu
drwxr-xr-x  2 angel angel    4096 Jan 19 15:49 bash

read 可以给多个变量赋值,正如下面脚本中所示:

#!/bin/bash
# read-multiple: read multiple values from keyboard
echo -n "Enter one or more values > "
read var1 var2 var3 var4 var5
echo "var1 = '$var1'"
echo "var2 = '$var2'"
echo "var3 = '$var3'"
echo "var4 = '$var4'"
echo "var5 = '$var5'"

执行结果:

[angel@linux ~]$ ./read_multiple.sh
Enter one or more values > a b c d e
var1 = 'a'
var2 = 'b'
var3 = 'c'
var4 = 'd'
var5 = 'e'
[angel@linux ~]$ 

如果read 命令接受到变量值数目少于期望的数字,那么额外的变量值为空,而多余的输入数据则会被包含到最后一个变量中。如果read 命令之后没有列出变量名,则一个shell 变量,REPLY,将会包含所有的输入:

#!/bin/bash
# read-single: read multiple values into default variable
echo -n "Enter one or more values > "
read
echo "REPLY = '$REPLY'"

执行结果:

[angel@linux ~]$ ./read.sh
Enter one or more values > a b c d
REPLY = 'a b c d'

2.选项:
read支持以下options:

选项说明
-a array把输入赋值到数组array 中,从索引号零开始
-d delimiter用字符串delimiter 中的第一个字符指示输入结束,而不是一个换行符
-e使用Readline 来处理输入。这使得与命令行相同的方式编辑输入。
-n num读取num 个输入字符,而不是整行。
-p prompt为输入显示提示信息,使用字符串promp
-rRaw mode. 不把反斜杠字符解释为转义字符
-sSilent mode. 不会在屏幕上显示输入的字符。当输入密码和其它确认信息的时候,这会很有帮助
-t超时. 几秒钟后终止输入。若输入超时,read 会返回一个非零退出状态
-u使用文件描述符fd 中的输入,而不是标准输入

五、位置参数

一个非常简单的脚本,显示变量$1到变量$3的变量参数:

#!/bin/bash
echo "
Number of parameters: $#
Read parameter1 is $1 
Read parameter2 is $2
Read parameter3 is $3
"

脚本执行结果如下:

[angel@linux ~]$ ./param.sh a b c
Number of parameters: 3
read parameter1 is a 
read parameter2 is b
read parameter3 is c

如果想确定参数个数,只需要使用"$#" 。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值