编程语言分类:
- 编译型
- 解释型
编译型语言:c、c++、c#
解释型语言:
内置型:shell、perl源码并入了linux kernel,提供内核级单条语句的效率
外置型:python、java、js,通过一个解释器(解释器本身的编译型语言例如c/c++写的可执行精灵程序)。外置型语言普遍比内置型语言的执行效率要高(总体上来说,单条未必)。通过预编译技术,将运行时解释的部分工作提前在运行前算好了(摘要、分类、预测),所以整体上其执行效率也非常高,其中java的执行效率接近c++,但是python的执行效率还是个渣渣。
各编程语言都有if switch for while 等与语法,也都要字符串、int、常量、数组等基本数据类型。
差异并不是特备的明显,所以一般的后端程序员,在工作过3年以上以后,任何语言都会一点。编程语言的主要差异在于:编译器的层次,和库的依赖方式。
这里提一下go语言:
golang曾经长期在解释型编程语言界混,然后由于创始人本来是写汇编编译器的,在经过市场实用几年以后,创始人将golang于他写的那个汇编器挂钩,一下提升了golang的层次,进化到了编译型编程语言。
一个程序的时间消耗:
- 程序员编码(一次性消耗)
- 编译(一次性消耗)
- 执行(多次消耗)。
那么程序效率来讲,指的就是执行时的消耗。
从执行效率来看,自然是编译型的代码执行效率高效。gcc g++ 在编译时就将代码转换为汇编,进而转换为机器语码,进而调用cpu门电路(移位寄存器、累加器、比较器、乘法器)。信息传递导致延迟,几乎接近机器码的语言,大大节省了在代码执行时信息传递的时间,不过在编译时需要更多的时间。
解释型编程语言,不需要编译的时间,或需要很少的预编译(java,Python),然后到字符串解析器,解析为最小单位的api调用,让后调用操作系统。
各种类型编程语言的运行示意图:
Linux应用开发的课程,第一部分是linux基本操作,第二部分是shell编程(解释型编程语言),第三部分是linux c/c++编程(编译型编程语言)。本节课程是第二部分。
shell编程
下面以一个hello world开篇:
python脚本:
[root@izwz93atpalb56zydy9bpyz 0-操作系统介绍]# cat test.py
#!/usr/bin/python
print('HELLO WORLD!')
[root@izwz93atpalb56zydy9bpyz 0-操作系统介绍]# ./test.py
HELLO WORLD!
[root@izwz93atpalb56zydy9bpyz 0-操作系统介绍]#
shell脚本
[root@izwz93atpalb56zydy9bpyz 0-操作系统介绍]# cat test.sh
#!/bin/bash
echo "hello world"
[root@izwz93atpalb56zydy9bpyz 0-操作系统介绍]# ./test.sh
hello world
[root@izwz93atpalb56zydy9bpyz 0-操作系统介绍]#
shell脚本的格式:
第一行固定以#!/bin/bash 或 #!/bin/sh开头,第二行开始每行一条命令。shell可以初步理解为,是你在终端输入命令的批量执行的集合。例如脚本test.sh内容为:
#!/bin/bash
pwd
ls
ifconfig
其执行效果为:
[root@izwz93atpalb56zydy9bpyz tmp]# ./test.sh
/tmp
Aegis-<Guid(5A2C30A2-A87D-490A-9281-6765EDAD7CBA)> redis-2.6.14 systemd-private-6c086a98f67e41439610fd69d85c8c01-cups.service-2ntpHp
main.cc redis-2.6.14.tar.gz systemd-private-6c086a98f67e41439610fd69d85c8c01-ntpd.service-WohG6p
redis redis-beta-3.tar.gz test.sh
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18.75.99 netmask 255.255.240.0 broadcast 172.18.79.255
ether 00:16:3e:02:ab:7d txqueuelen 1000 (Ethernet)
RX packets 62221 bytes 22156779 (21.1 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 58120 bytes 53103229 (50.6 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 2009424 bytes 613177808 (584.7 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2009424 bytes 613177808 (584.7 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
ether 52:54:00:a4:29:8d txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@izwz93atpalb56zydy9bpyz tmp]#
与三条命令的执行结果是一样的:
pwd的执行结果:
[root@izwz93atpalb56zydy9bpyz tmp]# pwd
/tmp
[root@izwz93atpalb56zydy9bpyz tmp]#
ls的执行结果
[root@izwz93atpalb56zydy9bpyz tmp]# ls
Aegis-<Guid(5A2C30A2-A87D-490A-9281-6765EDAD7CBA)> redis-2.6.14 systemd-private-6c086a98f67e41439610fd69d85c8c01-cups.service-2ntpHp
main.cc redis-2.6.14.tar.gz systemd-private-6c086a98f67e41439610fd69d85c8c01-ntpd.service-WohG6p
redis redis-beta-3.tar.gz test.sh
[root@izwz93atpalb56zydy9bpyz tmp]#
ifconfig 的执行结果:
[root@izwz93atpalb56zydy9bpyz tmp]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18.75.99 netmask 255.255.240.0 broadcast 172.18.79.255
ether 00:16:3e:02:ab:7d txqueuelen 1000 (Ethernet)
RX packets 62266 bytes 22160411 (21.1 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 58148 bytes 53112131 (50.6 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 2009424 bytes 613177808 (584.7 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2009424 bytes 613177808 (584.7 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
ether 52:54:00:a4:29:8d txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@izwz93atpalb56zydy9bpyz tmp]#
各种类型变量的定义
#!/bin/bash
set -e
echo "------------------shell r/w 变量定义---------------
VAR_CHAR='A'
VAR_INT=100
VAR_STR=\"hello world\"
VAR_DOUBLE=3.141592653
readonly VAR_CONST=\"hello i am const variable\"
"
VAR_CHAR='A'
VAR_INT=100
VAR_STR="hello world"
VAR_DOUBLE=3.141592653
readonly VAR_CONST="hello i am const variable"
echo
echo "------------------shell r/w 变量读取方式1----------"
echo $VAR_CHAR
echo $VAR_INT
echo $VAR_STR
echo $VAR_DOUBLE
echo $VAR_CONST
echo
echo "------------------shell r/w 变量读取方式2----------"
echo ${VAR_CHAR}
echo ${VAR_INT}
echo ${VAR_STR}
echo ${VAR_DOUBLE}
echo ${VAR_CONST}
echo
echo "------------------shell r/w 变量赋值---------------"
VAR_CHAR=1.1111
echo ${VAR_CHAR}
echo
echo "------------------shell r/w 变量加法---------------"
echo "add method 1---"
VAR_INT=`expr $VAR_INT + 1`
echo ${VAR_INT}
echo "add method 2---"
let VAR_INT++
echo ${VAR_INT}
echo "add method 3---"
((VAR_INT++))
echo ${VAR_INT}
echo "add method 4---"
VAR_INT=$[$VAR_INT + 1]
echo ${VAR_INT}
echo "add method 5---"
VAR_INT=$(($VAR_INT + 1))
echo ${VAR_INT}
echo
echo "------------------shell r/w 变量减法---------------"
echo "sub method 1---"
VAR_INT=`expr $VAR_INT - 1`
echo ${VAR_INT}
echo
echo "------------------shell r/w 变量乘法---------------"
echo "mul method 1---"
VAR_INT=$(($VAR_INT * 4))
echo ${VAR_INT}
echo
echo "------------------shell r/w 变量除法---------------"
echo "除法 method 1---"
VAR_INT=$(($VAR_INT / 2))
echo ${VAR_INT}
echo
echo "------------------shell r/w 变量删除---------------"
unset VAR_INT
echo ${VAR_INT}
echo
echo "------------------shell r/w 字符串变量追加---------------"
echo $VAR_STR
VAR_STR=$VAR_STR"-tail string"
echo $VAR_STR
echo $VAR_CONST
#VAR_CONST=$VAR_CONST"-tail string"
echo $VAR_CONST
echo
echo "------------------shell r/w 数组的定义1---------------"
array_tbl=("jacky" "1" '2' 3 4.12222)
echo ${array_tbl[0]}
echo ${array_tbl[1]}
echo ${array_tbl[2]}
echo ${array_tbl[3]}
echo ${array_tbl[4]}
echo
echo "------------------shell r/w 数组的定义2---------------"
array_tbl2[0]="robbe"
array_tbl2[1]=123456789
array_tbl2[2]='c'
array_tbl2[3]="你好"
echo ${array_tbl2[0]}
echo ${array_tbl2[1]}
echo ${array_tbl2[2]}
echo ${array_tbl2[3]}
echo "length of array array_tbl is:" ${#array_tbl[@]}
echo "length of array array_tbl is:" ${#array_tbl[*]}
echo "length of array array_tbl2 is:" ${#array_tbl2[*]}
echo "length of array_tbl[0] is:" ${#array_tbl[0]}
echo "length of array_tbl[1] is:" ${#array_tbl[1]}
echo "length of array_tbl2[1] is:" ${#array_tbl2[1]}
程序流程控制
- if语句
- for循环
- while循环
if 语句:
#!/bin/bash
echo "
if语句的语法格式:
if [ 条件 ];then
语句
fi
"
echo "
总共有6个关系运算符:
-eq 检测两个数据相等
-ne 检测连个数据不相等
-gt 左边 > 右边
-lt 左边 < 右边
-ge 左边 >= 右边
-le 左边 <= 右边
"
VAR_INT=10
if [ $VAR_INT -eq 10 ];then
echo "$VAR_INT 等于10"
elif [ $VAR_INT -ne 10 ];then
echo "VAR_INT 不等于10"
fi
for语句:
#!/bin/bash
echo "
for语句的语法格式:
for (( i=0; i<变量; i++ ))do
语句
done
"
array=(1 3 5 7 8 9 10 11 12 13)
for i in ${array[@]}
do
if [ $i -eq 10 ];then
echo ”$i 等于10“
fi
if [ $i -ne 10 ];then
echo ”$i 不等于10“
fi
if [ $i -gt 10 ];then
echo ”$i 大于10“
fi
if [ $i -lt 10 ];then
echo ”$i 小于10“
fi
if [ $i -ge 10 ];then
echo ”$i 大于等于10“
fi
if [ $i -le 10 ];then
echo ”$i 小于等于10“
fi
done
while语句:
#!/bin/bash
echo "--"
VAR=10
while [ $VAR -eq 10 ]
do
echo -n "please input which ranges is 15~20:"
read key_value
case $key_value in
15|16|17|18|19|20)
if [ $key_value == 20 ];then
echo "i will skip the following command because continue"
continue
fi
echo "输入的数据合法,$key_value"
;;
"exit")
echo "goodbye"
break
;;
*)
echo "输入数据不合法"
;;
esac
done
函数定义和引用
#!/bin/bash
echo "
shell 函数格式:
[ function ] funcname [()]
{
action;
[return ret;]
}
"
# 函数定义
function print_hello()
{
echo "参数个数为:$#"
if [ $# -ge 1 ];then
echo "第一个参数为:$1"
if [ $# -eq 2 ];then
echo "第二个参数为:"$2
fi
else
echo "$#"
fi
echo "函数调用"
}
print_hello "para1" 3.131592653
函数参数
#!/bin/bash
echo "
\$# cli命令行输入的参数个数(脚本名字后面跟的参数的数量,参数之间以空格为分隔符)
\$* 所有的命令行参数
\$$ 本脚本运行时,操作系统分配的id号
\$! 后台运行的最后一个进程的id号
\$@ 与$*相同,使用时是需要加引号,并在引号中返回每个参数
\$- 显示shell使用的当前选项,与set命令功能相同
\$? 显示最后一个命令的返回码。0表示最后一条命令($?往上紧挨着的那一条命令,不是指shell脚本的最后一行)没有出错,返回表示发生错误
"
echo "cli参数个数为: $#"
echo "本脚本的名字为: $0"
echo "第一个参数为: $1"
echo "第二个参数为: $2"
while :
do
echo "\$#=$#"
if [ $# == 0 ];then
break
fi
case $1 in
"para1")
echo "i am para1"
shift
;;
"para2")
echo "i am para2"
shift
;;
*)
shift
;;
esac
done
文件读写
#!/bin/bash
echo "创建多级目录"
mkdir -p ./dir1/dir2/dir3
echo "删除子目录"
rm -rf ./dir1/dir2
echo "创建文件"
touch ./dir1/log.txt
echo "文件写入内容"
echo "hello world" > ./dir1/log.txt
echo "hello jacky" >> ./dir1/log.txt
echo "第一种磁盘文件内容读取方式"
while read line
do
echo $line
done < ./dir1/log.txt
echo "第二种磁盘文件内容读取方式"
cat ./dir1/log.txt | while read line
do
echo $line
done
通过ftp工具下载文件
ftp客户端执行,需要在目标Linux节点安装了ftp服务端,Yum或apt安装轻量级ftp服务器:vsftpd
#!/bin/bash
# 函数功能: 从ftp服务器读取文件
# 参数: ip user pass fllename
function get_ftp_file() {
local IP=$1
local USER=$2
local PASS=$3
local FILE_NAME=$4
# echo "闹钟信号到来,访问ftp服务器"
ftp -v -n $IP<<EOF
user $USER
binary
lcd ./
prompt off
get $FILE_NAME
bye
close
EOF
}
# 从ftp服务器下载版本文件
get_ftp_file 127.0.0.1 ftp 123456 file1;
curl工具的使用
(要求搭建好目标http服务器)
curl上传文件到http文件服务器:
curl http://47.131.65.28:80/upload -F "file=@./file.txt"
curl发json包
curl -X post http://47.131.65.28:80/upload? -d"{\"cmd type\":\"ping node\"}"
curl发json文件
curl -X post http://47.131.65.28:80/upload? -d@js_test.json
js_test.json文件内容:
{
"cmd type":"get node list",
}
curl还可以发更为精准的Http包。掌握基础就行,如果以后你们工作需要用到时可自行百度。
wget文件下载
以下载redis源码为例:
[root@izwz93atpalb56zydy9bpyz tmp]# wget http://download.redis.io/releases/redis-2.6.14.tar.gz
--2020-01-07 15:44:15-- http://download.redis.io/releases/redis-2.6.14.tar.gz
Resolving download.redis.io (download.redis.io)... 109.74.203.151
Connecting to download.redis.io (download.redis.io)|109.74.203.151|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 995036 (972K) [application/x-gzip]
Saving to: ‘redis-2.6.14.tar.gz’
100%[========================================================================================================================>] 995,036 39.9KB/s in 21s
2020-01-07 15:44:37 (46.4 KB/s) - ‘redis-2.6.14.tar.gz’ saved [995036/995036]
[root@izwz93atpalb56zydy9bpyz tmp]# ll redis-2.6.14.tar.gz
-rw-r--r--. 1 root root 995036 Oct 9 2013 redis-2.6.14.tar.gz
[root@izwz93atpalb56zydy9bpyz tmp]#
shell高级:游戏开发
显示一个实时时钟:
#!/bin/bash
#
# Author: LKJ
# Date: 2013/5/14
# Email: liungkejin@gmail.com
#
asciinumber=(
' .XEEEEb ,:LHL :LEEEEEG .CNEEEEE8 bMNj NHKKEEEEEX 1LEEE1 KEEEEEEEKNMHH 8EEEEEL. cEEEEEO '
' MEEEUXEEE8 jNEEEEE EEEEHMEEEEU EEEELLEEEEc NEEEU 7EEEEEEEEEK :EEEEEEN, EEEEEEEEEEEEE OEEEGC8EEEM 1EEELOLEEE3 '
' NEE. OEEC EY" MEE OC LEEc :" EEE EEGEE3 8EN MEEM. :EE. 1EEj :EEO 1EE3 DEEc '
' ,EEj EEE HEE EEE cEE: EEU EEJ NEC EEE EEJ EEE EEE EEN KEE '
' HEE jEE1 NEE EEE EEE EEM EEJ EE LEE .. EEK DEEj :EE7 ,EE1 jEE '
' EEH EEZ KEE :EE1 .::jZEEG EEU EEJ .EEEEEENC EE77EEEEEEL NEE UEENj bEE7 .EEX :EE.'
'.EEZ EEM KEE EEK EEEEEEC .EEc EEC :X3DGMEEEEU 3EEEED.".GEEE. CEE. EEEEEEE EEEj :EEE '
' EEZ EEM KEE :EEK "jNEEZ :EE EE7 MEEU LEEb EEE .EE8 DEEL:.8EEEM NEEENMEEEHEE '
' EEN .EEG KEE bEEG 7EEM jEEN738ODDEEM3b EEE MEE 8EE, EEE EEE ,EEE .bEEEEC XEE '
' LEE 3EE: KEE .EEE, EEE LEEEEEEEEEEEEEE XEE 8EE cEE: NEE 7EE1 jEE1 :EE: '
' .EEc EEE KEE bEED EEE EE1 EEE EEX EEE 3EE: cEEc 7EEj CEEG '
' MEE7 NEE. EEE jEEK C EEE1 EEC j :EEE CEEG LEEj .EEU EEE: .EEE 1EEEJ '
' bEEEEEEEE. EEE NEEEEEEEEEEEE bEEEEEEEEEE7 EEd JEEEEEEEEEN jEEEEEEEEE7 .EEE KEEEEHEEEEL 8EEEEEEX '
' DEEEL7 CGD 3GD3DOGGGGGUX :DHEEEN8. bUd 7GNEEEMc 7LEEEX: 1XG JHEEEM1 COLIN" '
);
asciidot=(
' @@ '
' @@ '
);
len=${#asciinumber[@]};
#共有三个参数,
#第一个是所要打印的数字,
#第二个是之前打印的数字个数,
#第三个是之前打印的点的个数
function print_number {
start=$(($1*17));
start_y=$(($2*17+$3*4+$beg_y));
for (( i = 0; i < len; i++ )); do
echo -ne "\033[$((beg_x+i));${start_y}H\033[1;32m${asciinumber[$i]:$start:17}\033[0m";
done
}
#print_dot有两个参数
#第一个参数是之前打印的数字个数
#第二个参数是之前打印的点的个数
function print_dot {
local pt=$(($1*17+$2*4+beg_y));
for (( j = 0; j < 2; j++ )); do
echo -ne "\033[$((beg_x+j+3));${pt}H\033[1;32m${asciidot[$j]}\033[0m";
echo -ne "\033[$((beg_x+j+10));${pt}H\033[1;32m${asciidot[$j]}\033[0m";
done
}
function old_value {
orows=`tput lines`; beg_x=$((orows/2-6));
ocols=`tput cols`; beg_y=$((ocols/2-54));
ohur=$((10#`date +%H`));
omin=$((10#`date +%M`));
osec=$((10#`date +%S`));
print_number $((ohur/10)) 0 0; print_number $((ohur%10)) 1 0;
print_dot 2 0;
print_number $((omin/10)) 2 1; print_number $((omin%10)) 3 1;
print_dot 4 1;
print_number $((osec/10)) 4 2; print_number $((osec%10)) 5 2;
}
function print_all {
t_rows=`tput lines`; beg_x=$((t_rows/2-6));
t_cols=`tput cols`; beg_y=$((t_cols/2-54));
if [[ $t_rows -ne $orows || $t_cols -ne $ocols ]]; then
orows=$t_rows;
ocols=$t_cols;
check_win $orows $ocols;
old_value;
fi
hur=$((10#`date +%H`));
hft=$((hur/10)); hsd=$((hur%10));
if [[ $ohft -ne $hft ]]; then
print_number $hft 0 0;
ohft=$hft;
fi
if [[ $ohsd -ne $hsd ]]; then
print_number $hsd 1 0;
ohsd=$hsd;
fi
min=$((10#`date +%M`));
mft=$((min/10)); msd=$((min%10));
if [[ $omft -ne $mft ]]; then
print_number $mft 2 1;
omft=$mft;
fi
if [[ $omsd -ne $msd ]]; then
print_number $msd 3 1;
omsd=$msd;
fi
sec=$((10#`date +%S`)); #出现(())bug的原因:date +%S < 10 的时候会有前置0
#所以((08/10))会出错,但是使用expr不会出现错误,let也会有此错误
#解决方法是$((10#08/10));
sft=$((sec/10)); ssd=$((sec%10));
if [[ $osft -ne $sft ]]; then
print_number $sft 4 2;
osft=$sft;
fi
if [[ $ossd -ne $ssd ]]; then
print_number $ssd 5 2;
ossd=$ssd;
fi
}
function check_win {
if [[ $1 -lt 14 || $2 -lt 110 ]]; then
clear;
echo -ne "\033[8;15;120t"; #change the window size
fi
clear; #若窗口改变则重新刷新
}
function INIT {
tput smcup; #保存屏幕
check_win `tput lines` `tput cols`;
trap 'EXIT;' SIGINT; #将光标重新设置为白色
tput civis; #设置光标不可见
old_value;
}
function EXIT {
tput cvvis; #使光标可见
tput rmcup; #恢复屏幕
exit 0;
}
INIT;
while true; do
read -t 1 -n 1 anykey;
if [[ $? -eq 0 ]]; then
EXIT;
fi
print_all;
# if sleep 0.3 &> /dev/null; then
# sleep 1;
# fi;
done
exit 0;
贪吃蛇
#!/bin/bash
# filename: snake.sh
# snake game
# Author: LKJ 2013.5.17
good_game=(
' '
' G A M E O V E R ! '
' '
' Score: '
' press q to quit '
' press n to start a new game '
' press s to change the speed '
' '
);
game_start=(
' '
' ~~~ S N A K E ~~~ '
' '
' Author: LKJ '
' space or enter pause/play '
' q quit at any time '
' s change the speed '
' '
' Press <Enter> to start the game '
' '
);
snake_exit() { #退出游戏
stty echo; #恢复回显
tput rmcup; #恢复屏幕
tput cvvis; #恢复光标
exit 0;
}
draw_gui() { # 画边框
clear;
color="\033[34m*\033[0m";
for (( i = 0; i < $1; i++ )); do
echo -ne "\033[$i;0H${color}";
echo -ne "\033[$i;$2H${color}";
done
for (( i = 0; i <= $2; i++ )); do
echo -ne "\033[0;${i}H${color}";
echo -ne "\033[$1;${i}H${color}";
done
ch_speed 0;
echo -ne "\033[$Lines;$((yscore-10))H\033[36mScores: 0\033[0m";
echo -en "\033[$Lines;$((Cols-50))H\033[33mPress <space> or enter to pause game\033[0m";
}
snake_init() {
Lines=`tput lines`; Cols=`tput cols`; #得到屏幕的长宽
xline=$((Lines/2)); ycols=4; #开始的位置
xscore=$Lines; yscore=$((Cols/2)); #打印分数的位置
xcent=$xline; ycent=$yscore; #中心点位置
xrand=0; yrand=0; #随机点
sumscore=0; liveflag=1; #总分和点存在标记
sumnode=0; foodscore=0; #总共要加长的节点和点的分数
snake="0000 "; #初始化贪吃蛇
pos=(right right right right right); #开始节点的方向
xpt=($xline $xline $xline $xline $xline); #开始的各个节点的x坐标
ypt=(5 4 3 2 1); #开始的各个节点的y坐标
speed=(0.05 0.1 0.15); spk=${spk:-1}; #速度 默认速度
draw_gui $((Lines-1)) $Cols
}
game_pause() { #暂定游戏
echo -en "\033[$Lines;$((Cols-50))H\033[33mGame paused, Use space or enter key to continue\033[0m";
while read -n 1 space; do
[[ ${space:-enter} = enter ]] && \
echo -en "\033[$Lines;$((Cols-50))H\033[33mPress <space> or enter to pause game \033[0m" && return;
[[ ${space:-enter} = q ]] && snake_exit;
done
}
# $1 节点位置
update() { #更新各个节点坐标
case ${pos[$1]} in
right) ((ypt[$1]++));;
left) ((ypt[$1]--));;
down) ((xpt[$1]++));;
up) ((xpt[$1]--));;
esac
}
ch_speed() { #更新速度
[[ $# -eq 0 ]] && spk=$(((spk+1)%3));
case $spk in
0) temp="Fast ";;
1) temp="Medium";;
2) temp="Slow ";;
esac
echo -ne "\033[$Lines;3H\033[33mSpeed: $temp\033[0m";
}
Gooooo() { #更新方向
case ${key:-enter} in
j|J) [[ ${pos[0]} != "up" ]] && pos[0]="down";;
k|K) [[ ${pos[0]} != "down" ]] && pos[0]="up";;
h|H) [[ ${pos[0]} != "right" ]] && pos[0]="left";;
l|L) [[ ${pos[0]} != "left" ]] && pos[0]="right";;
s|S) ch_speed;;
q|Q) snake_exit;;
enter) game_pause;;
esac
}
add_node() { #增加节点
snake="0$snake";
pos=(${pos[0]} ${pos[@]});
xpt=(${xpt[0]} ${xpt[@]});
ypt=(${ypt[0]} ${ypt[@]});
update 0;
local x=${xpt[0]} y=${ypt[0]}
(( ((x>=$((Lines-1)))) || ((x<=1)) || ((y>=Cols)) || ((y<=1)) )) && return 1; #撞墙
for (( i = $((${#snake}-1)); i > 0; i-- )); do
(( ${xpt[0]} == ${xpt[$i]} && ${ypt[0]} == ${ypt[$i]} )) && return 1; #crashed
done
echo -ne "\033[${xpt[0]};${ypt[0]}H\033[32m${snake[@]:0:1}\033[0m";
return 0;
}
mk_random() { #产生随机点和随机数
xrand=$((RANDOM%(Lines-3)+2));
yrand=$((RANDOM%(Cols-2)+2));
foodscore=$((RANDOM%9+1));
echo -ne "\033[$xrand;${yrand}H$foodscore";
liveflag=0;
}
new_game() { #重新开始新游戏
snake_init;
while true; do
read -t ${speed[$spk]} -n 1 key;
[[ $? -eq 0 ]] && Gooooo;
((liveflag==0)) || mk_random;
if (( sumnode > 0 )); then
((sumnode--));
add_node; (($?==0)) || return 1;
else
update 0;
echo -ne "\033[${xpt[0]};${ypt[0]}H\033[32m${snake[@]:0:1}\033[0m";
for (( i = $((${#snake}-1)); i > 0; i-- )); do
update $i;
echo -ne "\033[${xpt[$i]};${ypt[$i]}H\033[32m${snake[@]:$i:1}\033[0m";
(( ${xpt[0]} == ${xpt[$i]} && ${ypt[0]} == ${ypt[$i]} )) && return 1; #crashed
[[ ${pos[$((i-1))]} = ${pos[$i]} ]] || pos[$i]=${pos[$((i-1))]};
done
fi
local x=${xpt[0]} y=${ypt[0]}
(( ((x>=$((Lines-1)))) || ((x<=1)) || ((y>=Cols)) || ((y<=1)) )) && return 1; #撞墙
(( x==xrand && y==yrand )) && ((liveflag=1)) && ((sumnode+=foodscore)) && ((sumscore+=foodscore));
echo -ne "\033[$xscore;$((yscore-2))H$sumscore";
done
}
print_good_game() {
local x=$((xcent-4)) y=$((ycent-25))
for (( i = 0; i < 8; i++ )); do
echo -ne "\033[$((x+i));${y}H\033[45m${good_game[$i]}\033[0m";
done
echo -ne "\033[$((x+3));$((ycent+1))H\033[45m${sumscore}\033[0m";
}
print_game_start() {
snake_init;
local x=$((xcent-5)) y=$((ycent-25))
for (( i = 0; i < 10; i++ )); do
echo -ne "\033[$((x+i));${y}H\033[45m${game_start[$i]}\033[0m";
done
while read -n 1 anykey; do
[[ ${anykey:-enter} = enter ]] && break;
[[ ${anykey:-enter} = q ]] && snake_exit;
[[ ${anykey:-enter} = s ]] && ch_speed;
done
while true; do
new_game;
print_good_game;
while read -n 1 anykey; do
[[ $anykey = n ]] && break;
[[ $anykey = q ]] && snake_exit;
done
done
}
game_main() {
trap 'snake_exit;' SIGTERM SIGINT;
stty -echo; #取消回显
tput civis; #隐藏光标
tput smcup; clear; #保存屏幕并清屏
print_game_start; #开始游戏
}
game_main;
结语:关于shell编程,还要更多的内容,不过上面的知识基本就足够你用到离开程序员这个行业了。我在工作中,遇到的大多数程序员,或者说叫码农(算不上真正的程序员的那种),他们的shell编程能力之弱,让人大跌眼镜。把shell程序写的能像博主这种水平的,目前尚未遇到过(可能没有去过大公司吧)。
上述内容是笔者之前讲过一个shell编程的视频课程的部分内容,发布在csdn上面,不过目前已经下架。
下节课开始,我们讲基于c/c++的 《linux 应用开发》。
由于本课程讲的是真实场景,博客内容全部以笔者的从业经历来编写,由浅入深,由点到面,逐步提升。
本课程计划讲18篇左右。
如果是想转型到linux应用开发,本专栏对你会有很多的帮助。能迅速带你从门外,到入门,再到中级的水准。水平的提高对应的,薪资会以k为最小单位去提升。
写一篇博客,排版内容需要花费1~2小时。后续课程需要订阅才能阅读全部内容。
《linux应用开发》技术交流qq群:528671785