COMP9044 Shell

shell

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Linux基本离不开shell,Shell 脚本(shell script),是一种为 shell 编写的脚本程序。bash (最常见的shell)is the most popular used shell for unix-like systems. 但这门课上我们要是用的是dash(内置最小脚本的内核)final 大概有4道考shell的题目 下面内容有来自菜鸟教程

shell 脚本示例

#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell

ShellScript
#!/bin/bash <br>
echo "Hello World !"
#!/usr/bin/env dash
# 这个环境就是vlab上的,final也是基于这个来的,他们有一些语法上的不同,尽量以这个course为主
echo "Hello World !" 

Shell变量


shell的所有变量默认为字符串,字符串可以用单引号,也可以用双引号,也可以不用引号。

ShellScript
# 定义变量时中间是没有空格的
x=5 
x="5" # 他们其实都是字符串
z=abc

#!/bin/dash 
now=$(date)
echo $now
# 打印Sun Jun 1 19:13:42 AEST 2025

Shell变量运算


$(( )) 这个格式是shell里面运算符,放在这里面的的变量可以进行运算

ShellScript
#!/bin/dash 
x=8
answer=$((x*x - 3*x + 2))
echo $answer # 输出 42

a=$b # 把变量 b 的值赋给 a。

[ $a == $b ] # 返回 false。
[ $a != $b ] # 返回 true。

# 输出内容
echo $(( $x + $ y))
# 计算并赋值
x=$(( $x + $y))

echo 基本相当于print


echo有两个选项 -n 和-e

  • -n选项就是do not output a trailing newline 不输出一个尾随换行符
  • -e echo命令会解析字符串中的转义字符,并将其替换为相应的特殊字符。这样,我们可以在输出中正确显示换行符、引号等特殊字符。
ShellScript
echo -e "Hello\nWorld"
# 会输出两行
# Hello 
# World
# 如果不使用-e选项,echo命令将直接输出字符串中的\n,而不会将其解析为换行符。

$ echo -n Hello Andrew
# 输出 Hello Andrew$

单引号 single quotes ‘ ‘


单引号字符串的限制:

  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
  • 单引号字符串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
ShellScript
$ echo '*** !@#$%^&*(){}[]:;"<>?,./` ***'
*** !@#$%^&*(){}[]:;"<>?,./`
***
$ echo 'this is "normal"'
this is "normal"

双引号 double quotes ” “


  • 双引号里可以有变量
  • 双引号里可以出现转义字符
ShellScript
$ answer=42
$ echo "The answer is $answer."
The answer is 42.
$ echo 'The answer is $answer.' # 单引号和双引号区别
The answer is $answer.

拼接字符串


ShellScript
your_name="runoob"
# 使用双引号拼接
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting  $greeting_1 # hello, runoob ! hello, runoob !

# 使用单引号拼接
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name} !'
echo $greeting_2  $greeting_3 # hello, runoob ! hello, ${your_name} !

I/O Redirection


stdin, stdout & stderr for a command can be directed to/from files 这里面几个可能是常用的

  • < infile connect stdin to the file infile
  • > outfile send stdout to the file outfile
  • >> outfile append stdout to the file outfile 重定向追加到某个位置,在原有文件的末尾添加内容
  • 2> outfile send stderr to the file outfile 重定向错误输出。
  • 2>> outfile append stderr to the file outfile 重定向错误追加输出到文件末尾。
  • >dev/null 重定向标准错误输出到/dev/null中
  • > outfile 2>&1 send stderr+stdout to outfile 将标准错误输出到外部 >&2 是简写形式
  • 1>&2 send stdout to stderr (handy for error messages)
  • «word here-document – previously discussed
  • «< string (in bash) here-string – a single line here-document

Shell 传递参数


脚本传递参数,脚本内获取参数的格式为 $nn 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数。理解这个对shell挺重要的

  • $0 the name of the command 执行文件的名字
  • $1 the first command-line argument 第一个参数
  • $2 the second command-line argument 第二个参数
  • … … 以此类推
  • $* 以一个单字符串显示所有向脚本传递的参数。
  • $# count of command-line arguments 传递到脚本的参数个数(总共有多少个参数)
  • "$@" command-line arguments as separate word 以”$1 $2$n” 的形式输出所有参数。
  • $? exit status of the most recent command 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
  • $$ process ID of this shell
ShellScript
#!/usr/bin/env dash
# author:菜鸟教程
# url:www.runoob.com

echo "Shell 传递参数实例!";
echo "第一个参数为:$1";

echo "参数个数为:$#";
echo "传递的参数作为一个字符串显示:$*";

# 执行脚本:
# $ chmod +x test.sh 
# $ ./test.sh 1 2 3
# Shell 传递参数实例!
# 第一个参数为:1
# 参数个数为:3
# 传递的参数作为一个字符串显示:1 2 3

$*$@ 区别:

  • 相同点:都是引用所有参数。
  • 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,则 ” * ” 等价于 “1 2 3″(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)。
  • 记住基本使用"$@"是会保持原样,不对打散将空格分隔开
ShellScript
echo "-----"
for i in "$*"; do
    echo $i
done

echo "-----"
for i in "$@"; do
    echo $i
done

# 执行脚本:
# $ chmod +x test.sh 
# $ ./test.sh 1 2 3
# -----
# 1 2 3
# -----
# 1
# 2
# 3

TEST命令


Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。 相当于判断符。

Number数值主要的命令有:

(括号里的是对应英语缩写,方便记住他,实际只能-eq这样的写法)

-eq (equal =)等于则为真
-ne (not euqal !=)不等于则为真
-gt (greater than >)大于则为真
-ge (greater or euqal >=)大于等于则为真
-lt (less than <)小于则为真
-le (less or euqal <=)小于等于则为真
ShellScript
num1=100
num2=100
if test $[num1] -eq $[num2]
then
    echo '两个数相等!'
else
    echo '两个数不相等!'
fi
# 两个数相等!

String字符的主要命令有:

假定变量 a 为 “abc”,变量 b 为 “efg”:

=等于则为真[ a = b ] 返回 false。
!=不相等则为真[ a != b ] 返回 true。
-z 字符串字符串的长度为零则为真[ -z $a ] 返回 false。
-n 字符串字符串的长度不为零则为真[ -n “$a” ] 返回 true
$检测字符串是否不为空,不为空返回 true。[ $a ] 返回 true。
ShellScript
num1="ru1noob"
num2="runoob"
if test $num1 = $num2
then
    echo '两个字符串相等!'
else
    echo '两个字符串不相等!'
fi
# 两个字符串不相等!

file文件的主要命令有:

文件判断命令挺多的,Final是闭卷考试,所以多多练习熟悉一些。

-e 文件名判断对象是否存在
-r 文件名判断对象是否存在,并且可读
-w 文件名判断对象是否存在,并且可写
-x 文件名判断对象是否存在,并且可执行
-s 文件名判断对象是否存在,并且长度不为0
-d 文件名判断对象是否存在,并且为目录
-f 文件名判断对象是否存在,并且为常规文件
-c 文件名如果文件存在且为字符型特殊文件则为真
-b 文件名如果文件存在且为块特殊文件则为真
ShellScript
cd /bin
if test -e ./bash
then
    echo '文件已存在!'
else
    echo '文件不存在!'
fi
# 文件已存在!

Shell 还提供了boolean operators (and/or/not): -a -o ! 与( -a )、或( -o )、非( ! )三个逻辑操作符用于将测试条件连接起来,其优先级为: ! 最高, -a 次之, -o 最低。

ShellScript
cd /bin
if test -e ./notFile -o -e ./bash
then
    echo '至少有一个文件存在!'
else
    echo '两个文件都不存在'
fi

# 至少有一个文件存在!

# final 通常不要 -a
test "$x" -ge 10 -a "$x" -le 20
# 建议下 ⾯ 的写法
if "$x" -ge "10"; then
	if "$x" -le 20; then
	fi
fi

test 还有一个写法是可以用[]来代替

下面这个例子是打印1…N的整数

ShellScript
# Print the integers 1..n with no argument checking
last=$1
number=1
while test $number -le "$last" # 这里用的是test
do
    echo $number
    number=$((number + 1))
done

# 下面变成[]
last=$1
number=1
while [ $number -le "$last" ] # 这里用的是[] 注意两边的空格一定要有
do
    echo $number
    number=$((number + 1))
done

# $ ./seq.v0.sh 3
# 1
# 2
# 3

Shell退出状态(exit status)


;, &&, ||, {}, () 一些Example

  • ;所有命令都会执行,不管前面有没有成功 相当于似顺序执行:
ShellScript
cmd1 ; cmd2 ; cmd3
  • &&:逻辑与就相当于and。 如果前一条命令成功(exit status 为 0),才执行下一条,某条命令失败,就停止执行。
ShellScript
cmd1 && cmd2 && cmd3

# 如果 a.out 存在且可执行(-x)就运行它
test -x a.out && ./a.out 

a=10
b=20

if [ $a -lt 100 ] && [ $b -gt 100 ]
then
   echo "返回 true"
else
   echo "返回 false"
fi
# 返回 false
  • ||:逻辑或相当于or 一条命令失败(非 0),才执行下一条
ShellScript
cmd1 || cmd2 || cmd3

# 如果目录不存在才创建
test -d tmp || mkdir tmp 
  • {}:命令块(在当前 shell 中执行)花括号内的命令会在当前 shell 中执行
ShellScript
{ cmd1; cmd2; }

# 如果目录不存在则创建,再赋予权限,只有在目录存在或成功创建的情况下才执行 chmod
{ test -d tmp || mkdir tmp; } && chmod 755 tmp

# 简化
mkdir -p tmp && chmod 755 tmp
  • ():子 Shell(subshell) 命令会在新的子 Shell 中执行 所有变量或目录的变化不会影响外部 shell
ShellScript
( cmd1; cmd2 )
  • 简单对比 {}() ()里面相当于一个命令
ShellScript
$ cd /usr/share
$ x=123
# 在子 Shell 中执行 cd /tmp; x=abc
# 子 Shell 是一个隔离的环境,变量 x 和目录更改只存在于里面
$ ( cd /tmp; x=abc; )
$ echo $x
123   # 123 变量没有变
$ pwd
/usr/share # 目录也没变

# 花括号内容是在当前 Shell 中执行的!
$ { cd /tmp; x=abc; }
$ echo $x
abd # 花括号内容是在当前 Shell 中执行的!
$ pwd
/tmp # 当前 Shell 的变量 x 真的变了
符号作用范围是否影响变量和目录何时使用
{}当前 Shell✅ 会改变想修改变量、目录等环境时使用
()子 Shell(隔离)❌ 不会改变临时环境,避免污染时使用

if 语句


if elif else fi 最后是要以fi为结束,当这个if语句结束后, if 后面通常要跟个then将要执行的语句放后面,if如果跟then在同一行前面要加; ;then 如果另起一行就可以不用加; 他们的格式通常顶头写。

常见if语句:

ShellScript
#!/usr/bin/env dash

var="test"
if [ -n "$var" ] && [ "$var"="test" ]; then
	echo "The variable is not empty and equals 'test'."
else 
	echo "The variable is either empty or does not equal 'test'."
fi
# 输出"The variable is not empty and equals 'test'."

if diff -q a.txt a1.txt > /dev/null # 这是常用的对比文件的不同
then																# then 另起一行
	echo 'same'
else
	echo 'difference'
fi

for 语句


常见的for… in,break & continue一样适用。后面几执行的语句要记得加do 和 done

常见语句

ShellScript
# shell中在命令参数中找最大值和最小值

#!/usr/bin/env das
min=$1
max=$2

for num in $@ # 遍历所有的参数
do
    if [ $num -lt $min ]; then
        min=$num
    fi
    if [ $num -gt $max ]; then
        max=$num
    fi
done

echo "Min: $min"
echo "Max: $max"

# ./test.sh 100 1 2 99 3 24 1000 6 11
# Min: 1
# Max: 1000

while语句


跟for语句一样,加do然后完成以done结尾。 break & continue一样适用在while

ShellScript
# 求和 计算1到100的和
start=1
end=10
sum=0

while [ $start -le $end ]; do
	sum=$(($sum + $start))
	start=$(($start + 1))
done
echo "$sum"

# 输出 55

Function函数


shell 可以用户定义函数,然后在shell脚本中可以随便调用。

shell functions have this form:

ShellScript
# 可以带 function fun() 定义,也可以直接 fun() 定义,不带任何参数
# 参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果
$ fun(){
	commands
}

# 这是一个带return的语句的函数
funWithReturn(){
    echo "这个函数会对输入的两个数字进行相加运算..."
    echo "输入第一个数字: "
    # 下面的aNum已经是变量了 后面想要调用它就是用$aNum的形式
    read aNum 
    echo "输入第二个数字: "
    read anotherNum
    echo "两个数字分别为 $aNum$anotherNum !"
    return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"

# terminal 中运行会是下面的内容
这个函数会对输入的两个数字进行相加运算...
输入第一个数字: 
1 # 这里首先会是等待用户输入内容
输入第二个数字: 
2 # 然后继续等待...输入完成后显示下面的内容
两个数字分别为 1  2 !
输入的两个数字之和为 3 !

read命令


Read是一个shell内置功能,它可以将一行输入读入变量。有些类似于python中input()

  • EOF非零退出状态 non-zero exit status on EOF
  • 去掉换行符 newline is stripped
  • 除非变量IFS使用,否则取消前导和尾随空格 leading and trailing whitespace stripped unless variable IFS unset
  • -r 选项能识别\的转义符,否则只会当做字符串识别
ShellScript
# 在terminal中输入
$ read v # 这时命令行会等待输出
hello world # 输入hello world就会将
$ echo $v 
hello world # 会打印出 hello world

$ $ read a b c # 相当于给三个变量 
1 2 3 4 5 # 接下来给a b c 分别输入变量
$ echo "a='$a' b='$b' c='$c'"
a='1' b='2' c='3 4 5' 

# 下面是一个例子 运行这个.sh会先打印"Do you like learning Shell? " 然后等待用户的输入,根据用户的输入来给对应的response
echo -n "Do you like learning Shell? "
read answer
# get first letter of answer connverted to lower case
# Use cut to get the first character and tr to convert it to lower case
# cut -c1 是只获取第一个字符
answer="$(
    echo "$answer"| 
    cut -c1|
    tr A-Z a-z
)"
if test "$answer" = "y"
then
    response=":)"
elif test "$answer" = "n"
then
    response=":("
else
    response="??"
fi
Back to top arrow

 

评论

发表回复

目录