最简单 Shell 程序解析及运行 #
#!/bin/sh 是指此脚本使用/bin/sh 来解释执行,#!是特殊的表示符,其后面跟的是此解释此脚本的 shell 的路径。
Shell 程序第一行规范建议
- 建议写法
#! /bin/sh
- 强烈不建议写法—— #!型注释
- #! 其它注释内容
- 两种运行方式
./
sh
Shell 程序调试方式 #
命令 | 选项 | 功能说明 |
---|---|---|
sh -n 程序名 | 纯粹性 解释分析 | 解释但不执行命令(用于检查程序语法错误) |
sh -x 程序名 | 显示替换结果程序并执行 | 在变量替换之后、执行命令之前,显示程序的每一有效行(非空且非注释行) |
sh -v 程序名 | 显示原始程序并执行 | 在执行之前,按输入的原样显示输出程序中所有各行(包括空行、注释行) |
set -x | 打开(命令)回显 | 跟踪程序的执行(主要用于 Shell 程序中) |
set +x | 关闭(命令)回显 | 关闭跟踪功能(主要用于 Shell 程序中) |
局部变量应用编程 #
Shell 变量赋值与引用
- Shell 变量赋值
- <变量名>=<初始值>
- 譬如:fileName=“zgsFile.txt”
- 注意等号两边不能有空格!!!
- Shell 变量引用
- $<变量名>
"$fileName"、“$fileName”、‘$fileName’
或任何引号外 $fileName 有效'$fileName'
无效($ 亦按普通字符处理)$fileName
比较特殊(按命令串处理)
- 清理变量 unset varName
空格在linux中时作为一个很典型的分隔符,比如string1=this is astring,这样执行就会报错。为了避免这个问题,因此就产生了单引号和双引号。他们的区别在于,单引号将剥夺其中的所有字符的特殊含义,而双引号中的'$'(参数替换)和'`'(命令替换)是例外。所以,两者基本上没有什么区别,除非在内容中遇到了参数替换符$和命令替换符`。
Shell 变量分类
- 局部变量(本地变量)
- 自己定义的变量
- 环境变量(类似于全局变量)
- 可以自己定义并全局化
- 譬如 $PATH
- 预定义变量(特殊变量)
$+【*#$?!】
- 位置变量(类似于 C 程序的命令行参数)
- $+【数字】
环境变量及 export 命令 #
查看系统环境变量取值 -env 命令
BASH脚本基础:环境变量PS2介绍_bash ps2-CSDN博客
$ echo $HOME
home/zhaigaoshou2018
$ echo $LANG
en_US.UTF-8
$ echo $TERM
xterm-256color
$ echo $PS2
>
$ echo $PATH
opt/ros/kinetic/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Shell 程序的环境变量
- 定义方式类似于局部变量,但在作为环境变量使用前必须通过 export 命令进行导出
- 环境变量生命周期和作用域涵盖对应所有各级子孙进程
- 系统环境变量生命周期和作用域涵盖所有用户及各子孙进程,最好在.profile 文件中定义
export 命令解析
- 是变量(名)而非仅仅变量取值的传递
位置变量及特殊变量应用编程 #
Shell 程序的位置变量
- 类似于 C 程序的命令行参数,用来对命令行中各对应位置的参数进行描述
- $0 对应 Shell 命令或 Shell 程序名本身
- $1、$2、…、$9 分别对应传入的第 1 个参数、第 2 参数、…、第 9 个参数
- 当实际参数大于 9 个时,需要用 shift 命令来移动位置参数
- 每执行一次 shift n 命令,最前面的 n 个传入参数将被移去,于是第 n+1 个参数成为 $1,以此类推
- 缺省情况下,n 等于 1
Shell 命令中的特殊变量
$*
命令行中的传入参数序列
$#
命令行中的传入参数的个数
$?
前一个命令返回的结果(状态)值,0为正常
$$
当前Shell进程的进程标识符PID值
$!
最近访问的后台进程的进程标识符PID值
条件判断控制结构应用编程 #
if-else 基本代码结构
- command-list1 或 command-list2 等两处命令行部分均可嵌套使用 if 条件判断控制结构
- else 分支可无
if [ "$varZGS" = valueZGS ]
then
command-list1
else
command-list2
fi
- command-list1 或 command-list2 等三处命令行部分均可嵌套使用 if 条件判断控制结构,且 then 命令行与 fi 之间的 elif-then 命令行可有连续多个
if [ "$varZGS1" = valueZGS1 ]
then
command-list1
elif [ "$varZGS2" = valueZGS2 ]
then
command-list2
else
command-list3
fi
分支判断控制结构应用编程 #
case-Shell 例程
case "$cmdID" in
d|D) date ;;
w|W) who ;;
s|S) echo "Hello! `who`" ;;
c|C) echo "Hello! China!" ;;
*) echo "$cmdID is not a valid choice!"
echo "Run the program and try again!"
exit 1 ;;
esac
exit 0
case 代码基本结构
case "$varZGS" in
pattern1) command-list1 ;;
pattern2) command-list2 ;;
pattern3) command-list3 ;;
pattern4) command-list4 ;;
……
*) command-list ;;
esac
循环控制结构应用编程
while-Shell 例程
#! /bin/sh
Sum=0
i=0
while [ $i != "100" ]
do
i=`expr $i + 1`
Sum=`expr $Sum + $i`
done
echo "Sum-from-1-to-$i = $Sum"
-
expr command in Linux with examples - GeeksforGeeks
- Basic operations like addition, subtraction, multiplication, division, and modulus on integers.
- Evaluating regular expressions, string operations like substring, length of strings etc.
while 循环结构编程要旨
- 基本代码结构
while [ "$varZGS" != valueZGS ]
do
command-list
done
- while 循环执行过程
- 首先判断循环条件是否成立
- 若不成立,则转③结束循环;否则,进入循环体执行有关命令,然后转①
- 循环结束
until 循环结构编程要旨
- 基本代码结构
until [ $varZGS = valueZGS ]
do
command-list
done
- until 循环执行过程
- 首先判断循环条件是否成立
- 若成立,则转③结束循环;否则,进入循环体执行有关命令,然后转①
- 循环结束
for shell 例程
#! /bin/sh
Sum=0
for zI in 1 2 3 4 5 6
do
Sum=`expr $Sum + $zI`
done
echo "SumOf[1 2 3 4 5 6] = $Sum"
for 循环结构 1 编程要旨
- 基本代码结构
for varZGS
do
command-list
done
- for 循环执行过程
- 首先判断 Shell 程序还有无传入参数
- 若无,则转③结束循环;否则,将最前面的传入参数赋值给循环变量,进入循环体执行有关命令,然后传入参数执行左移操作,转①
- 循环结束
for 循环结构 2 编程要旨
- 基本代码结构
for zI in zList
do
command-list
done
- for 循环执行过程
- 首先判断循环变量取值列表还有无数值
- 若无,则转③结束循环;否则,将最前面的数值赋值给循环变量,进入循环体执行有关命令,然后有关取值列表执行左移操作,转①
- 循环结束
for 循环结构 3 编程要旨
- 基本代码结构
for varZGS in `cmd`
do
command-list
done
break 与 continue 编程要旨
逆序显示命令行参数的 shell 例程
#! /bin/sh
# A continue shell-script
count=$#
cmd='echo'
while true
do
cmd="$cmd \$$count"
count=`expr $count - 1`
[ $count -gt 0 ] && continue
eval $cmd
exit 0
done
#! /bin/sh
# A break shell-script
count=$#
cmd='echo'
while true
do
cmd="$cmd \$$count"
count=`expr $count - 1`
[ $count -eq 0 ] && break
done
eval $cmd
拷贝若干文件的 shell 例程
#! /bin/sh
# A shell script for copying files to directory
eval dir=\$$#
if [ -d $dir ]
then
echo $dir
cmd=cp
while [ $1 ]
do
if [ -f $1 ]
then
{
cmd="$cmd $1"
echo $cmd
}
else
echo "$1 is not a file"
fi
shift
done
cmd="$cmd $dir"
echo $cmd
$cmd
fi
显示若干文件内容的 Shell 例程
#! /bin/sh
# A shell script for displaying contents of specified files
echo "Error messgages:" > errFile
exitStatus=0
if [ $# = 0 ]
then
{
echo "At least one argument is needed!" >> errFile
echo "Usage: shApp-CatFilesBv file1 [file2 … fileN]" >> errFile
exitStatus=1
}
fi
while [ $1 ]
do
if [ -f "$1" ] && [ -r "$1" ]
then
{
i=1
while read LINE
do
echo "$i#: " $LINE
i=`expr $i + 1`
done < "$1"
}
else
echo "$1 is a not ordinary file or it can't be read!!!" >> errFile
exitStatus=2
fi
shift
done
监控系统用户的 shell 例程
#! /bin/sh
# A shell script for monitoring log-user
who | sort > prev
while true
do
sleep 10
who | sort > curr
echo "logged out:"
comm -23 prev curr #显示只在`prev`中而不在`curr`中的行,即已注销的用户
echo "================="
echo "logged in:"
comm -13 prev curr #显示只在`curr`中而不在`prev`中的行,即新登录的用户
echo "================="
mv curr prev
done
函数应用编程 #
- 函数定义
function_name()
{
<命令行序列>
return [n]
}
- 调用方式
function_name [<参数序列>]
Shell 文件中函数调用要旨
- 命令行中定义的函数
- 存在于 B-Shell 内存空间
- 文件中定义的 Shell 函数使用方式
source <ShellFunFileName>
- 若想使有关函数永久保留在 Shell 空间,则需将语句
“.~/<ShellFunFileName>”
写入文件.profile 和.bashrc 中,从而在启动 Shell 时读取这些函数文件加载到 Shell 空间中【/etc/profile.d/*.sh】
- 查看(Shell 空间中的)函数与导出函数
- set 命令、export <函数名>【使子进程可用】
#! /bin/sh
# A shell script demonstrating functions for Jia/Jian/Cheng/Chu
Add()
{
echo -e "add: $1 + $2 = \c"
echo "$1 + $2" | bc
}
Sub()
{
echo -e "sub: $1 - $2 = \c"
echo "$1 - $2" | bc
}
Mult()
{
echo -e "mult: $1 * $2 = \c"
echo "$1 * $2" | bc
}
Div()
{
echo -e "div: $1 / $2 = \c"
echo "$1 / $2" | bc
}
Mod()
{
echo -e "mod: $1 % $2 = \c"
echo "$1 % $2" | bc
}
- 函数必须先定义,后使用
- 函数在当前环境中运行,可共享其主调程序中的变量,还允许以给位置参量赋值的方式向函数传递参数
- 可使用 local 功能在函数内部创建局部变量
- return 命令返回主调程序;exit 命令结束整个程序
- 可用 export -f 把函数导出到子 Shell 中
- 函数可以递归,且递归调用次数没有限制