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
#!/bin/bash <br>
echo "Hello World !"
#!/usr/bin/env dash
# 这个环境就是vlab上的,final也是基于这个来的,他们有一些语法上的不同,尽量以这个course为主
echo "Hello World !" Shell变量
shell的所有变量默认为字符串,字符串可以用单引号,也可以用双引号,也可以不用引号。
# 定义变量时中间是没有空格的
x=5
x="5" # 他们其实都是字符串
z=abc
#!/bin/dash
now=$(date)
echo $now
# 打印Sun Jun 1 19:13:42 AEST 2025Shell变量运算
$(( )) 这个格式是shell里面运算符,放在这里面的的变量可以进行运算
#!/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命令会解析字符串中的转义字符,并将其替换为相应的特殊字符。这样,我们可以在输出中正确显示换行符、引号等特殊字符。
echo -e "Hello\nWorld"
# 会输出两行
# Hello
# World
# 如果不使用-e选项,echo命令将直接输出字符串中的\n,而不会将其解析为换行符。
$ echo -n Hello Andrew
# 输出 Hello Andrew$单引号 single quotes ‘ ‘
单引号字符串的限制:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字符串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
$ echo '*** !@#$%^&*(){}[]:;"<>?,./` ***'
*** !@#$%^&*(){}[]:;"<>?,./`
***
$ echo 'this is "normal"'
this is "normal"双引号 double quotes ” “
- 双引号里可以有变量
- 双引号里可以出现转义字符
$ answer=42
$ echo "The answer is $answer."
The answer is 42.
$ echo 'The answer is $answer.' # 单引号和双引号区别
The answer is $answer.拼接字符串
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 传递参数
脚本传递参数,脚本内获取参数的格式为 $n,n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数。理解这个对shell挺重要的
$0the name of the command 执行文件的名字$1the first command-line argument 第一个参数$2the 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
#!/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”(传递了三个参数)。
- 记住基本使用
"$@"是会保持原样,不对打散将空格分隔开
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
# 3TEST命令
Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。 相当于判断符。
Number数值主要的命令有:
(括号里的是对应英语缩写,方便记住他,实际只能-eq这样的写法)
| -eq (equal =) | 等于则为真 |
|---|---|
| -ne (not euqal !=) | 不等于则为真 |
| -gt (greater than >) | 大于则为真 |
| -ge (greater or euqal >=) | 大于等于则为真 |
| -lt (less than <) | 小于则为真 |
| -le (less or euqal <=) | 小于等于则为真 |
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。 |
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 文件名 | 如果文件存在且为块特殊文件则为真 |
cd /bin
if test -e ./bash
then
echo '文件已存在!'
else
echo '文件不存在!'
fi
# 文件已存在!
Shell 还提供了boolean operators (and/or/not): -a -o ! 与( -a )、或( -o )、非( ! )三个逻辑操作符用于将测试条件连接起来,其优先级为: ! 最高, -a 次之, -o 最低。
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
fitest 还有一个写法是可以用[]来代替
下面这个例子是打印1…N的整数
# 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
;所有命令都会执行,不管前面有没有成功 相当于似顺序执行:
cmd1 ; cmd2 ; cmd3&&:逻辑与就相当于and。 如果前一条命令成功(exit status 为 0),才执行下一条,某条命令失败,就停止执行。
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),才执行下一条
cmd1 || cmd2 || cmd3
# 如果目录不存在才创建
test -d tmp || mkdir tmp {}:命令块(在当前 shell 中执行)花括号内的命令会在当前 shell 中执行
{ cmd1; cmd2; }
# 如果目录不存在则创建,再赋予权限,只有在目录存在或成功创建的情况下才执行 chmod
{ test -d tmp || mkdir tmp; } && chmod 755 tmp
# 简化
mkdir -p tmp && chmod 755 tmp
():子 Shell(subshell) 命令会在新的子 Shell 中执行 所有变量或目录的变化不会影响外部 shell
( cmd1; cmd2 )- 简单对比
{}和()()里面相当于一个命令
$ 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语句:
#!/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'
fifor 语句
常见的for… in,break & continue一样适用。后面几执行的语句要记得加do 和 done
常见语句
# 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: 1000while语句
跟for语句一样,加do然后完成以done结尾。 break & continue一样适用在while
# 求和 计算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:
# 可以带 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 选项能识别\的转义符,否则只会当做字符串识别
# 在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
发表回复
要发表评论,您必须先登录。