前端程序员有时会遇到部署项目的情况,有时需要看懂后台或者运维写的脚本。如果转型AI,数据分析和模型训练也经常用到shell编程,掌握shell编程,你的编程之路会越走越宽。
sudo cat /etc/shells, tab 一下是补全命令,tab 两下查看命令
/bin/sh /bin/bash /sbin/nologin /bin/dash /bin/tcsh /bin/csh
6 种 shell 解析器, 常用前两种,位于系统 bin 目录
cd /bin -> ll | grep shell 可以看出来 sh 最终调用的还是 bash
查看系统默认解析器: echo $SHELL->/bin/shell
脚本格式
脚本以#!/bin/bash 开头(/bin/bash 就是指定的解析器),写#!/bin/sh 也是一样的,#在这里不是注释,而是个命令
shell 脚本示例
echo “helloworld”
把它放到脚本里, cd 默认切换到家目录, mkdir datas, cd datas
touch helloworld.sh 创建 shell 文件,写上.sh 更语义化
vim helloworld.sh 编辑 helloworld.sh
#!/bin/bash
echo "hello shell"
执行脚本:sh helloworld.sh 或者 bash helloworld.sh 也可以
./helloworld.sh 执行的时候提示权限不够, 之前是 shell 解析器帮你执行
而./helloworld.sh 是自己调用执行,需要自己有执行权限
chmod 777 helloworld.sh, ./相对路径这种方式以后用的多
多命令处理案例
来到某个目录创建文本文件,在文本文件中增加"like shell"
touch batch.sh -> vim batch.sh
#!/bin/bash
cd /home/yu/
touch bigdata.txt
echo "I love big data" >> bigdata.txt
ll 查看有无执行权限,没有执行权限则执行 bash batch.sh
执行完后查看 cat bigdata.txt
系统变量和自定义变量
变量定义规则
字母数字下划线组成,不能以数字开头,环境变量名建议大写
变量默认都是字符串类型,无法直接进行数值运算
sum=1+1 echo $sum 得到 1+1
变量的值如果有空格,需要用双引号或者单引号括起来
可以把变量提升为全局环境变量,供其他 shell 使用
vim helloworld.sh 修改编辑 helloworld.sh
#!/bin/bash
echo "hello shell"
echo $sum
执行./helloworld.sh 却打印不出来 1+1, $sum 在这个文件里,而当前定义的 sum 是在控制台上,二者不在一个进程里面,属于定义的局部变量,如果控制台上 export sum,相当于晋升为全局变量,然后再执行./helloworld.sh 就能打印出来 1+1
各种 home 变量,kafka_home、hadoop_home 都需要是全局有效的
#!/bin/bash
echo "$0 $1 $2"
bash parameter.sh 或者
chmod 777 parameter.sh
bash parameter.sh aaa 输出 parameter.sh aaa
#!/bin/bash
echo "$0 $1 $2"
echo $#
测试 bash parameter.sh aa bb cc 就会得到 3
#!/bin/bash
echo "$0 $1 $2"
echo $#
echo $*
echo $@
测试 bash parameter.sh aa bb cc 二者都输出 aa bb cc
如何进行加减乘除的运算
$((运算表达式))或者$[运算表达式]
或者 expr +,-,\*,/,% 加减乘(乘是斜杠*)除取余
expr 运算符间要有空格
expr 3+2 输出 3+2; expr 3 +2 语法错误; expr 3 + 2 得到 5
(2+3)*4
expr `expr 2 + 3` \* 4
s=$[(2+3)*4] 然后 echo s 结果一样
运算符两边空格可有可无
[ condition ] condition 的前后都要有空格,条件非空即为 true
[]返回 false
if [ 条件判断表达式 ];then
程序
fi
或者
if [ 条件判断表达式 ]
then
程序
fi
#!/bin/bash
# if [ $1 -eq 1 ];then
if [ $1 -eq 1 ]
then
echo "aaa"
elif [ $1 -eq 2 ]
then
echo "bbb"
fi
bash if.sh // 没有写参数,也没有对参数进行合法性检查
bash if.sh 1 // aaa
bash if.sh 2 // bbb
bash if.sh 3 //
case $变量名 in
"值1")
如果变量值为1则执行
;;
...
*)
上面都不是
;;
esac
#!/bin/bash
case $1 in
1)
echo "aaa"
;;
2)
echo "bbb"
;;
*)
echo "ccc"
esac
sh case.sh 1 // aaa
for(( 初始值;循环控制条件;变量变化 ))
do
程序
done
#!/bin/bash
s=0
for((i=1;i<=100;i++)) // i不需要定义
do
s=$[$s+$i]// 不支持s+=
done
echo $s
bash for.sh // 5050
$*、$@
for 变量 in 值1 值2 值3
do
程序
done
touch for2.sh
vim for2.sh
#!/bin/bash
for i in $*
do
echo "para is $i"
done
for j in $@
do
echo "para is $j"
done
bash for2.sh aa bb cc // 输出没区别
引号引起来变成一个整体
#!/bin/bash
for i in "$*"
do
echo "para is $i"
done
for j in "$@"
do
echo "para is $j"
done
bash for2.sh aa bb cc
"$*"
整体一次会把所有参数输出,代表循环了一次 para is aa bb cc
"$@"
输入多少参数还是会循环多少次
while [ 条件表达式 ]
do
程序
done
touch while.sh
vim while.sh
#!/bin/bash
# 变量的值小于100, 变量的值$i,取值的话需要先定义
i=1
s=0
while [ $i -le 100 ]
do
s=$[$s + $i]
i=$[$i + 1]
done
echo $s
bash while.sh
主要用于后面自定义函数的时候用到的一些命令
read(选项)(参数)
选项:-p 指定读取时的提示符;-t 指定读取时等待的时间(秒)
参数:变量指定读取值的变量名
touch read.sh
vim read.sh
#!/bin/bash
read -t 5 -p "Enter your name in 5 s" name
echo $name
$name
也可以作为后续函数的参数
basename /home/yu/parameter.sh
# 结果得到parameter.sh
basename /home/yu/parameter.sh .sh
# 结果得到parameter
dirname /home/yu/parameter.sh
# 结果 /home/yu
$?
的方式[ function ] funname[()]
{
Action;
[return int;]
}
funname
必须在调用函数地址之前先声明函数,shell 脚本是逐行执行,不像其他有的语言会先编译
函数返回值只能通过$?
系统变量获得,可以显式的加 return 返回,
如果不加 return 将以最后一条命令运行结果作为返回值,return 后跟数值 n(0-255)
#!/bin/bash
function sum()
{
s=0
s=$[$1+$2]
echo $s
}
read -p "input your parameter1:" p1
read -p "input your parameter2:" p2
sum $p1 $p2
bash sum.sh
只列举常用工具和参数,更多内容可以查看相关的 shell 手册
aa aaa
bb bbb
cc ccc
aa aaa
bb bbb
cc ccc
将"BB BBB"插入到 sed.txt 第二行下
sed “2a BB BBB” sed.txt // a 是增加,第二行是 2a, 原文件并不会改变
删除 sed.txt 中有 cc 的行
sed "/BB/d" sed.txt
将 sed.txt 中 aa 替换为 AA
sed "s/aa/AA/g" sed.txt
// 加 g 是全局替换
将第二行删除,并将 cc 替换为 CC
sed -e "2d" -e "s/cc/CC/g" sed.txt
awk [选项参数] 'pattern1{action} pattern2{action2}...' filename
示例
sudo cp /etc/passwd ./
输出 passwd 文件以 root 关键字开头的所有行,并输出该行的第七列
把切换用户的命令为 su username,接着从普通用户切换到 root 用户,还可以使用命令 sudo su,最后在终端输入 exit 或 logout 或使用快捷方式 ctrl 加 d,可以退回到原来用户; root 设置用户密码,passwd 用户, 查看密码状态,passwd -S 用户
改变文件的所有者和所属组,sudo chown yu:yu passwd
awk -F : '/^root/ {print $7}' passwd
搜索 passwd 文件以 root 关键字开头的所有行,并输出该行的第一列和第七列,中间以逗号分割
awk -F : '/^root/ {print $1","$7}' passwd
只显示/etc/passwd 的第一列和第七列,以逗号分割,且在所有行前面添加列名 user、shell,在最后一行添加“yu, /bin/yuyu”
awk -F : 'BEGIN{print "user,shell"} {print $1","$7} END{print "yu, /bin/yuyu"}' passwd
// 第二个 action 没有正则条件
将 passwd 文件中的用户 id 增加数值 1 并输出
awk -F : -v i=1 '{print $3+i}' passwd
// 这个地方比较特殊用 i 而不是$i
内置变量
FILENAME 文件名; NR 已读记录数; NF 浏览记录的域的个数(切割后,列的个数)
awk -F : '{print FILENAME "," NR "," NF}' passwd
ifconfig eth0 | grep "inet addr" | awk -F : '{print $2}' | awk -F " " '{print $1}'
awk '/^$/{print NR}' sed.txt
sort -t : -nrk 2 sort.sh