• 主页
  • 相册
  • 随笔
  • 目录
  • 存档
Total 244
Search AboutMe

  • 主页
  • 相册
  • 随笔
  • 目录
  • 存档

shell脚本编程基础

2020-05-16

1. 实验内容

  • 用bash编写一个图片批处理脚本,实现以下功能:
    • 支持命令行参数方式使用不同功能
    • 支持对指定目录下所有支持格式的图片文件进行批处理
    • 支持以下常见图片批处理功能的单独使用或组合使用
      • 支持对jpeg格式图片进行图片质量压缩
      • 支持对jpeg/png/svg格式图片在保持原始宽高比的前提下压缩分辨率
      • 支持对图片批量添加自定义文本水印
      • 支持批量重命名(统一添加文件名前缀或后缀,不影响原始文件扩展名)
      • 支持将png/svg图片统一转换为jpg格式图片
  • 用bash编写一个文本批处理脚本,对附件:2014世界杯运动员数据分别进行批量处理完成相应的数据统计任务:
    • 统计不同年龄区间范围(20岁以下、[20-30]、30岁以上)的球员数量、百分比
    • 统计不同场上位置的球员数量、百分比
    • 名字最长的球员是谁?名字最短的球员是谁?
    • 年龄最大的球员是谁?年龄最小的球员是谁?
  • 用bash编写一个文本批处理脚本,对附件:Web服务器访问日志分别进行批量处理完成相应的数据统计任务:
    • 统计访问来源主机TOP 100和分别对应出现的总次数
    • 统计访问来源主机TOP 100 IP和分别对应出现的总次数
    • 统计最频繁被访问的URL TOP 100
    • 统计不同响应状态码的出现次数和对应百分比
    • 分别统计不同4XX状态码对应的TOP 10 URL和对应出现的总次数
    • 给定URL输出TOP 100访问来源主机

2. 实验环境

  • wsl: ubuntu18.04
  • 文件
    • 附件:2014世界杯运动员数据
    • 附件:Web服务器访问日志
      • sudo apt install p7zip p7zip-full p7zip-rar

3. 实验原理

3.1. shell

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。

Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。


Linux 的 Shell 种类众多,常见的有:

  • Bourne Shell(/usr/bin/sh或/bin/sh)
  • Bourne Again Shell(/bin/bash)
  • C Shell(/usr/bin/csh)
  • K Shell(/usr/bin/ksh)
  • Shell for Root(/sbin/sh)
  • ……

3.2. Shell 脚本(shell script)

以Bourne Shell为例

3.2.1. philosophy

  • The most important criteria must be a clear, readable layout.
  • Second is avoiding unnecessary commands.
    • cat /tmp/myfile | grep "mystring"就会比grep "mystring" /tmp/myfile要慢

3.2.2. Hello World

1
2
3
4
5
6
$ echo '#!/bin/sh' > my-script.sh
$ echo 'echo Hello World' >> my-script.sh
$ chmod 755 my-script.sh
$ ./my-script.sh
Hello World
$
  • #!/bin/sh:tells Unix that the file is to be executed by /bin/sh
    • #!:这是一个特殊的指令,Unix会特别处理。其意味着,即使你使用 csh、ksh 或其他任何交互式 shell,下面的内容也应该被 Bourne shell 解释。
  • echo Hello World:runs a command: echo, with two parameters, or arguments - the first is “Hello”; the second is “World”.
    • echo will automatically put a single space between its parameters.

3.2.3. 变量(Variables)

3.2.3.1. 1
1
2
MY_MESSAGE="Hello World"
echo $MY_MESSAGE

The shell does not care about types of variables; they may store strings, integers, real numbers - anything you like.

In truth, these are all stored as strings, but routines which expect a number can treat them as such.

3.2.3.2. 2

使用read命令交互式地设置变量名:read MY_MESSAGE

  • read命令会自动在其输入的周围加上双引号,这样就可以正确处理空格
3.2.3.3. 3

Variables in the Bourne shell do not have to be declared

But if you try to read an undeclared variable, the result is the empty string

3.2.3.4. 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh
echo "MYVAR is: $MYVAR"
MYVAR="hi there"
echo "MYVAR is: $MYVAR"

$ MYVAR=hello
$ ./myvar2.sh
MYVAR is:
MYVAR is: hi there

$ export MYVAR
$ ./myvar2.sh
MYVAR is: hello
MYVAR is: hi there
  • 这改变了MYVAR的值。但没有把这个值传回给你的交互式shell
  • 一旦shell脚本退出,它的环境就会被破坏。但MYVAR会在你的交互式shell中保留其值hello。
  • In order to receive environment changes back from the script, we must source(源化) the script.
  • 我们可以通过”.”(dot)命令来源化脚本
1
2
3
4
5
$ . ./myvar2.sh
MYVAR is: hello
MYVAR is: hi there
$ echo $MYVAR
hi there
  • 这就是你的.profile或.bash_profile文件的工作原理。
    • 注意,在这种情况下,我们不需要导出MYVAR。

      在Unix shell中,点号被称为点命令(.),是执行或打开电脑文件的命令。

      点命令的第一个引数是文件名;人们可以在第二个引数中指定参数。如果没有指定任何参数,该文件将获得一组在当前上下文中可用的位置参数;如果指定参数,该文件将只收到所指定的参数。在任何情况下,位置参数$0会是当前上下文的$0。

      该文件不必有执行权限。点命令通常被用来定义当前进程中可访问的环境变量。相比直接执行该文件,使用点命令执行该文件不会打开新的进程,文件所定义环境变量适用于当前的进程或当前的Shell。

      • source:wikipedia
3.2.3.5. 5

把变量本身用大括号括起来,定义这个变量的起始位置

1
2
echo "I will create you a file called ${USER_NAME}_file"
touch "${USER_NAME}_file"
  • 注意"${USER_NAME}_file "周围的引号;不加引号可能导致多个文件的创建
3.2.3.6. 6
  • The variable $0 is the basename of the program as it was called.

  • $1 .. $9 are the first 9 additional parameters the script was called with.

  • The variable $@ is all parameters

  • The variable $*, is similar, but does not preserve any whitespace, and quoting, so “File with spaces” becomes “File” “with” “spaces”

    • As a general rule, use $@ and avoid $*.
  • $# is the number of parameters the script was called with.

  • $? contains the exit value of the last run command

    1
    2
    3
    if [ "$?" -ne "0" ]; then
    echo "Sorry, we had a problem there!"
    fi
  • The $$ variable is the PID (Process IDentifier) of the currently running shell. This can be useful for creating temporary files, such as /tmp/my-script.$$ which is useful if many instances of the script could be run at the same time, and they all need their own temporary files.

  • The $! variable is the PID of the last run background process

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
echo "I was called with $# parameters"
echo "My name is $0"
echo "My first parameter is $1"
echo "My second parameter is $2"
echo "All parameters are $@"

$ ./var3.sh hello world earth
I was called with 3 parameters
My name is ./var3.sh
My first parameter is hello
My second parameter is world
All parameters are hello world earth
3.2.3.7. 7

shift

  • 移动位置参数
  • shift [n]
    • 将位置参数$n, $n+1…重命名为$1, $2…。
    • n(可选):大于等于1且小于等于参数个数的整数,默认为1。
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env bash
# 显示前三个位置参数。
echo "$1 $2 $3"
# 移除前两个位置参数,并将$3重命名为$1,之后的以此类推。
shift 2
echo "$1 $2 $3"

$ sh test.sh q w e r t
q w e
e r t
1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh
while [ "$#" -gt "0" ]
do
echo "\$1 is $1"
shift
done

$ sudo sh ./2.sh a b c
$1 is a
$1 is b
$1 is c

3.2.4. 通配符(Wildcards)

*

3.2.5. 转义字符(Escape Characters)

3.2.5.1. 1

$ echo "Hello \"World\""

  • 值得一提的是echo "Hello "World""中只有一个参数
3.2.5.2. 2

Most characters (*,', etc) are not interpreted (ie, they are taken literally) by means of placing them in double quotes (“”).

1
2
3
4
$ echo *txt
ip-primer.txt raid1+0.txt
$ echo "*txt"
*txt
3.2.5.3. 3

However, ",$,`, and \ are still interpreted by the shell, even when they’re in double quotes.

  • The backslash () character is used to mark these special characters

3.2.6. 循环(Loops)

3.2.6.1. for
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh
for i in hello 1 * 2 goodbye
do
echo "Looping ... i is set to $i"
done

$ ./1.sh
Looping ... i is set to hello
Looping ... i is set to 1
Looping ... i is set to 1.sh
Looping ... i is set to 2
Looping ... i is set to goodbye
3.2.6.2. while
1
2
3
4
5
6
7
8
#!/bin/sh
INPUT_STRING=hello
while [ "$INPUT_STRING" != "bye" ]
do
echo "Please type something in (bye to quit)"
read INPUT_STRING
echo "You typed: $INPUT_STRING"
done
  • while :永远为真
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
while read f
do
case $f in
hello) echo English ;;
howdy) echo American ;;
gday) echo Australian ;;
bonjour) echo French ;;
"guten tag") echo German ;;
*) echo Unknown Language: $f
;;
esac
done < myfile
  • 它从文件myfile中读取,并对每一行,告诉你它认为正在使用的语言。每一行都必须以LF(换行)结尾–如果cat myfile没有以空行结尾,那最后一行将不被处理
3.2.6.3. 3

一种简写

1
2
3
4
5
6
for runlevel in 0 1 2 3 4 5 6 S
do
mkdir rc${runlevel}.d
done

mkdir rc{0,1,2,3,4,5,6,S}.d

更多例子

1
ls -ld {,usr,usr/local}/{bin,sbin,lib}

3.2.7. 测试(Test)

3.2.7.1. 1
1
2
$ ls -l /usr/bin/test
-rwxr-xr-x 1 root root 35368 Mar 27 2000 /usr/bin/test
  • This means that ‘[‘ is actually a program, just like ls and other programs, so it must be surrounded by spaces:if [$foo = "bar" ],will not work; it is interpreted as if test$foo = "bar" ]
    • 有些shell也接受”==”来进行字符串比较;这是不方便移植的,对于字符串应该使用”=”,对于整数应该使用”-eq”
    • Test最常通过if和while语句间接调用。这也是如果你创建了一个名为test的程序并尝试运行它,你会遇到困难的原因,因为这个shell内建的程序会被调用,而不是你的程序!这也是为什么你会遇到困难的原因。

test

  • shell环境中测试条件表达式工具
    1
    2
    3
    test File1 –ef File2    两个文件是否为同一个文件,可用于硬连接。主要判断两个文件是否指向同一个inode。
    test File1 –nt File2 判断文件1是否比文件2新
    test File1 –ot File2 判断文件1比是否文件2旧

3.2.8. 运算符

1
2
3
4
5
6
7
8
9
10
11
12
-e filename 	如果 filename存在,则为真 	[ -e /var/log/syslog ]
-d filename 如果 filename为目录,则为真 [ -d /tmp/mydir ]
-f filename 如果 filename为常规文件,则为真 [ -f /usr/bin/grep ]
-L filename 如果 filename为符号链接,则为真 [ -L /usr/bin/grep ]
-r filename 如果 filename可读,则为真 [ -r /var/log/syslog ]
-w filename 如果 filename可写,则为真 [ -w /var/mytmp.txt ]
-x filename 如果 filename可执行,则为真 [ -L /usr/bin/grep ]
filename1-nt filename2 如果 filename1比 filename2新,则为真 [ /tmp/install/etc/services -nt /etc/services ]
filename1-ot filename2 如果 filename1比 filename2旧,则为真 [ /boot/bzImage -ot arch/i386/boot/bzImage ]
字符串比较运算符 (请注意引号的使用,这是防止空格扰乱代码的好方法)
-z string 如果 string长度为零,则为真 [ -z "$myvar" ]
-n string 如果 string长度非零,则为真 [ -n "$myvar" ]

3.2.9. 分支(Case)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/bin/sh

echo "Please talk to me ..."
while :
do
read INPUT_STRING
case $INPUT_STRING in
hello)
echo "Hello yourself!"
;;
bye)
echo "See you again!"
break
;;
*)
echo "Sorry, I don't understand"
;;
esac
done
echo
echo "That's all folks!"

$ ./talk.sh
Please talk to me ...
hello
Hello yourself!
What do you think of politics?
Sorry, I don't understand
bye
See you again!

That's all folks!
$
  • if we wanted to exit the script completely then we would use the command exit instead of break.

3.2.10. 函数(Functions)

3.2.10.1. 1

一个函数可以用四种不同的方式返回一个值

  • 改变一个或多个变量的状态
  • 使用exit命令结束shell脚本
  • 使用return命令结束函数,并将提供的值返回到 shell 脚本的调用部分
  • echo输出到stdout,就像c=expr $a + $b被抓取一样,会被调用者抓取

与c语言函数不同的是,shell函数不能改变参数,但它可以改变全局参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/sh
# A simple script with a function...

add_a_user()
{
USER=$1
PASSWORD=$2
shift; shift;
# Having shifted twice, the rest is now comments ...
COMMENTS=$@
echo "Adding user $USER ..."
echo useradd -c "$COMMENTS" $USER
echo passwd $USER $PASSWORD
echo "Added user $USER ($COMMENTS) with pass $PASSWORD"
}

###
# Main body of script starts here
###
echo "Start of script..."
add_a_user bob letmein Bob Holness the presenter
add_a_user fred badpassword Fred Durst the singer
add_a_user bilko worsepassword Sgt. Bilko the role model
echo "End of script..."
  • 以()结尾来标识自己是一个函数声明
  • seradd和passwd命令的前缀是用echo来表示–这是一个有用的调试技术,可以检查正确的命令是否被执行
3.2.10.2. 2

变量的作用域

Basically, there is no scoping, other than the parameters ($1, $2, $@, etc).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Taking the following simple code segment:

#!/bin/sh

myfunc()
{
echo "I was called as : $@"
x=2
}

### Main script starts here

echo "Script was called with $@"
x=1
echo "x is $x"
myfunc 1 2 3
echo "x is $x"

$ scope.sh a b c
Script was called with a b c
x is 1
I was called as : 1 2 3
x is 2
  • The $@ parameters are changed within the function to reflect how the function was called
3.2.10.3. 3

A function will be called in a sub-shell if its output is piped somewhere else - that is, “myfunc 1 2 3 | tee out.log” will still say “x is 1” the second time around.

with the simple example of “ls | grep foo”, then grep has to be started first, with its stdin then tied to the stdout of ls once ls starts

3.3. 外部程序(External Programs)

1
2
3
4
5
6
$ grep "^${USER}:" /etc/passwd | cut -d: -f5
Steve Parker

$ MYNAME=`grep "^${USER}:" /etc/passwd | cut -d: -f5`
$ echo $MYNAME
Steve Parker

4. 实验内容

4.1. 1

  • 支持命令行参数方式使用不同功能
    • case
  • 对指定目录下所有支持格式的图片文件进行批处理
    • 通配符*
  • 支持对jpeg格式图片进行图片质量压缩
    1
    2
    3
    4
    Compress() {
    jpegoptim $P -m $Q
    echo compress successfully
    }
  • 支持对图片批量添加自定义文本水印
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Watermark() {
    if [ -f "$P" ]; then
    convert $P -gravity SouthEast -pointsize 80 -font URW-Palladio-L-Bold -fill "#fffdc3" -annotate +10+10 $W $P
    echo Watermark adding successfully
    elif [ -d "$P" ]; then
    for f in $P; do
    convert $P -gravity SouthEast -pointsize 80 -font URW-Palladio-L-Bold -fill "#fffdc3" -annotate +10+10 $W $f
    echo Watermark adding successfully
    done
    fi
    }
  • 支持批量重命名(统一添加文件名前缀或后缀,不影响原始文件扩展名)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    Prefix() {
    export PN=$PN
    if [ -f "$P" ]; then
    cd $(echo ${P%/*})
    rename 's/^/\Q$ENV{PN}\E/' ${P##*/}
    elif [ -d "$P" ]; then
    cd $P
    rename 's/^/\Q$ENV{PN}\E/' *
    fi
    echo Prefix adding successfully
    }
    Suffix() {
    export SN=$SN
    if [ -f "$P" ]; then
    cd $(echo ${P%/*})
    rename 's/(.*)\.(.*)/$1\Q$ENV{SN}\E.$2/' ${P##*/}
    elif [ -d "$P" ]; then
    cd $P
    rename 's/(.*)\.(.*)/$1\Q$ENV{SN}\E.$2/' *
    fi
    echo Suffix adding successfully
    }

    It works by either replacing the (zero-length) start of the strings (^) or the start followed by an optional prefix string with prefix.

  • 单独文件

  • 批量操作
  • 支持将png/svg图片统一转换为jpg格式图片
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Convert() {
    if [ -f "$P" ]; then
    cd $(echo ${P%/*})
    E=${P##*/}
    convert ./"${E}" ./"${E%.*}.jpg"
    elif [ -d "$P" ]; then
    cd $P
    for f in *.png; do
    convert ./"$f" ./"${f%.png}.jpg"
    done
    for f in *.svg; do
    convert ./"$f" ./"${f%.svg}.jpg"
    done
    fi
    echo Convert successfully
    }

4.2. 2

  • 统计不同年龄区间范围(20岁以下、[20-30]、30岁以上)的球员数量、百分比

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Age() {
    var=$(tail -n +2 $P | cut -f 6)
    v1=0
    v2=0
    v3=0
    for i in $var; do
    if [ "$i" -lt "20" ]; then
    v1=$(($v1 + 1))
    elif [ "$i" -gt "30" ]; then
    v3=$(($v3 + 1))
    else
    v2=$(($v2 + 1))
    fi
    done
    all=$(($v1 + $v2 + $v3))
    echo "below 20:" $v1 "\t" "$(($v1 * 100 / $all))%"
    echo "between 20 and 30:" $v2 "\t" "$(($v2 * 100 / $all))%"
    echo "above 30:" $v3 "\t" "$(($v3 * 100 / $all))%"
    }
  • 统计不同场上位置的球员数量、百分比

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    Position() {
    var=$(tail -n +2 $P | cut -f 5)
    v1=0
    v2=0
    v3=0
    v4=0
    for i in $var; do
    case $i in
    Defender)
    v1=$(($v1 + 1))
    ;;
    Forward)
    v2=$(($v2 + 1))
    ;;
    Goalie)
    v3=$(($v3 + 1))
    ;;
    Midfielder)
    v4=$(($v4 + 1))
    ;;
    esac
    done
    all=$(($v1 + $v2 + $v3 + $v4))
    echo "Defender:" $v1 "\t" "$(($v1 * 100 / $all))%"
    echo "Forward:" $v2 "\t" "$(($v2 * 100 / $all))%"
    echo "Goalie:" $v3 "\t" "$(($v3 * 100 / $all))%"
    echo "Midfielder:" $v4 "\t" "$(($v4 * 100 / $all))%"
    }
  • 名字最长的球员是谁?名字最短的球员是谁?

    1
    2
    3
    4
    5
    6
    Name() {
    v1=$(tail -n +2 $P | cut -f 9 | awk '{ print length, $0 }' | sort -n -s | cut -d ' ' -f 2- | head -n1)
    v2=$(tail -n +2 $P | cut -f 9 | awk '{ print length, $0 }' | sort -n -s | cut -d ' ' -f 2- | tail -n1)
    echo "min length name :" $v1
    echo "max length name :" $v2
    }
  • 年龄最大的球员是谁?年龄最小的球员是谁?

    1
    2
    3
    4
    5
    6
    Age2() {
    v1=$(tail -n +2 $P | cut -f 6,9 | sort -g | head -n1)
    v2=$(tail -n +2 $P | cut -f 6,9 | sort -g | tail -n1)
    echo "youngest :" $v1
    echo "oldest :" $v2
    }

4.3. 3

  • 统计访问来源主机TOP 100和分别对应出现的总次数
    1
    2
    3
    4
    5
    6
    7
    8
    Host() {
    echo '#####\n# Top 100 SourceHost\n#####'
    var=$(tail -n +2 $P | cut -f 1 | sort | uniq -c | sort -nr | head -n 100)
    IFS=''
    for i in $var; do
    echo $i
    done
    }
  • 统计访问来源主机TOP 100 IP和分别对应出现的总次数
    1
    2
    3
    4
    5
    6
    7
    8
    IP() {
    echo '#####\n# Top 100 HostIP\n#####'
    var=$(tail -n +2 $P | cut -f 1 | grep -E "(([0-9]{1,3}\.){3}[0-9]{1,3}$)" | sort | uniq -c | sort -nr | head -n 100)
    IFS=''
    for i in $var; do
    echo $i
    done
    }
  • 统计最频繁被访问的URL TOP 100
    1
    2
    3
    4
    5
    6
    7
    8
    URL() {
    echo '#####\n# Top 100 URL\n#####'
    var=$(tail -n +2 $P | cut -f 5 | sort | uniq -c | sort -nr | head -n 100)
    IFS=''
    for i in $var; do
    echo $i
    done
    }
  • 统计不同响应状态码的出现次数和对应百分比
    1
    2
    3
    4
    STATUS() {
    echo '#####\n# Status Code\n#####'
    tail -n +2 $P | cut -f 6 | sort | uniq -c | sort -nr | awk '{ sum+=$1;++i;x[i]=$1;y[i]=$2 } END{ j=1; while(j<=i){ print x[j]*100/sum"%",y[j];++j} }'
    }
  • 分别统计不同4XX状态码对应的TOP 10 URL和对应出现的总次数
    1
    2
    3
    4
    5
    6
    7
    8
    STATUS4() {
    echo '#####\n#Top 100 Status Code 4xx\n#####'
    var=$(tail -n +2 $P | cut -f 6 | awk '$1 >=400 && $1 < 500' | sort | uniq)
    for i in $var; do
    echo $i :
    tail -n +2 $P | cut -f 5,6 | awk -v i=$i '$2 == i' | sort | uniq -c | sort -nr | head -n 100
    done
    }
  • 给定URL输出TOP 100访问来源主机
    1
    2
    3
    4
    URL2() {
    echo '#####\n#Top 100 URL SourceHost\n#####'
    tail -n +2 $P | cut -f 1,5 | awk -v H=$H '$2 ==H { print $1 } '| sort | uniq -c | sort -nr | head -n 100
    }
    结果仅以Top10为例

5. 参考资料

  • Shell 教程 | 菜鸟教程
  • The Shell Scripting Tutorial
  • shell script - Using a variable with rename command - Unix & Linux Stack Exchange
  • Linux shell字符串截取、替换、删除以及trim_运维_aabond的博客-CSDN博客
  • command line - Converting multiple image files from JPEG to PDF format - Unix & Linux Stack Exchange
  • linux shell 指令 诸如-d, -f, -e之类的判断表达式 - sincoolvip - 博客园
  • Lab
  • Shell
  • Operating System
  • Linux
  • Lab
awk笔记
Netplan
  1. 1. 1. 实验内容
  2. 2. 2. 实验环境
  3. 3. 3. 实验原理
    1. 3.1. 3.1. shell
    2. 3.2. 3.2. Shell 脚本(shell script)
      1. 3.2.1. 3.2.1. philosophy
      2. 3.2.2. 3.2.2. Hello World
      3. 3.2.3. 3.2.3. 变量(Variables)
        1. 3.2.3.1. 3.2.3.1. 1
        2. 3.2.3.2. 3.2.3.2. 2
        3. 3.2.3.3. 3.2.3.3. 3
        4. 3.2.3.4. 3.2.3.4. 4
        5. 3.2.3.5. 3.2.3.5. 5
        6. 3.2.3.6. 3.2.3.6. 6
        7. 3.2.3.7. 3.2.3.7. 7
      4. 3.2.4. 3.2.4. 通配符(Wildcards)
      5. 3.2.5. 3.2.5. 转义字符(Escape Characters)
        1. 3.2.5.1. 3.2.5.1. 1
        2. 3.2.5.2. 3.2.5.2. 2
        3. 3.2.5.3. 3.2.5.3. 3
      6. 3.2.6. 3.2.6. 循环(Loops)
        1. 3.2.6.1. 3.2.6.1. for
        2. 3.2.6.2. 3.2.6.2. while
        3. 3.2.6.3. 3.2.6.3. 3
      7. 3.2.7. 3.2.7. 测试(Test)
        1. 3.2.7.1. 3.2.7.1. 1
      8. 3.2.8. 3.2.8. 运算符
      9. 3.2.9. 3.2.9. 分支(Case)
      10. 3.2.10. 3.2.10. 函数(Functions)
        1. 3.2.10.1. 3.2.10.1. 1
        2. 3.2.10.2. 3.2.10.2. 2
        3. 3.2.10.3. 3.2.10.3. 3
    3. 3.3. 3.3. 外部程序(External Programs)
  4. 4. 4. 实验内容
    1. 4.1. 4.1. 1
    2. 4.2. 4.2. 2
    3. 4.3. 4.3. 3
  5. 5. 5. 参考资料
© 2024 何决云 载入天数...