为了提高项目安装部署的成功率,降低安装部署过程中人为因素造成风险,一直考虑将整个流程自动化。为了实现这个诉求,最近一直在给项目上输出各种 shell 脚本,然而习惯了 python 的强大,且也是许久未触及 linux系统,导致写起 shell 脚本总是手生。通过这次项目的锻炼,不得不感慨到“一日不读口生,一日不写手生 ”。接下来就将本次一边编写一遍温习一遍总结的经验向大家做个分享,也希望本分享能带给你切实的帮助~
👑一、权限问题 先讲一下权限问题,在普通用户下是没有root权限。 简单理解就 root权限 具有操作根(系统)目录的全部权限,而普通用户不可以
1 2 3 4 5 6 7 # 普通用户可以之直接操作的目录路径有以下 1. /home/用户名 # 这个俗称用户目录/家目录,桌面 文档 等文件夹都在这里 2. /tmp 缓存目录 # 在普通用户下 $USER 表示用户名 1. /home/$USER # 表示用户目录。 2. $HOME # 也表示用户目录
先了解一下就可以,普通用户下临时提权 root 权限。 sudo su 或者 sudo -i 命令行提示符有 $ 变成 #
🍇二、什么是文本文件,要如何创建 1.文本编辑器可以直接编辑的,比如 .txt 、 .sh 、 .js 、 .html ,SHELL脚本的后缀名是.sh 2.右键桌面就可以直接创建文本文件 3.创建文本文件有一个专有命令 touch
[ touch ] 1 2 3 4 # 在桌面创建文本文件 touch /home/$USER/桌面/123.txt # 在 /opt 创建文本文件,因为普通用户不能直接操作 /opt 所以提权操作sudo sudo touch /opt/123.txt
[ echo ] 1 2 3 4 5 6 7 8 9 10 11 12 13 echo 的作用就是打印字符串 # 在终端输入 echo "123456" 就会显示 123456 echo 也可以用来创建文本文件 # 在桌面创建123.txt echo "" > /home/$USER/桌面/123.txt # 在桌面创建123.txt 123456保存到123.txt echo "123456" > /home/$USER/桌面/123.txt # 在桌面创建123.txt 123456保存到123.txt echo "123456" >> /home/$USER/桌面/123.txt
👿三、常用命令 [ > 和 >> ] 的区别 [ > ] 清空 如果桌面有个文本文件 456.txt 里面有 456
1 2 3 > /home/$USER /桌面/456.txt 456.txt 里面有 456就被清空了 echo "123456" > /home/$USER/桌面/456.txt # 这个时候原来的数据456就被清空了,并把123456保存在456.txt
[ >> ] 追加
1 2 echo "123456" >> /home/$USER/桌面/456.txt # 这个时候原来的数据456会保存,并把123456保存在456.txt,位置就是在保存456的后一行。
总结:在终端创建文本文件 通常有两种方法 1.touch 创建,只能创建空的文本文件 2.echo 创建,可以创建有内容的文本文件
[ 变量名称与变量的值 ] 变量名称 一般使用驼峰命名法 就是单词手写字母大写,比如**LinuxMint=”123456”**,使用一个变量 ${LinuxMint} 简写 $LinuxMint
LinuxMint是变量名称 123456是变量LinuxMint的值
注意事项:变量直之间的 单 双 引导的区别 下面使用实例来讲解
1 2 3 4 5 6 7 LinuxMint="123456" # 双引号 echo "${LinuxMint}" # 显示 123456 # 单引号 echo '${LinuxMint}' # 显示 ${LinuxMint}
显然 双引号 是执行了 LinuxMint变量 输出 123456 然而 单引号 没有执行 LinuxMint变量 把 ${LinuxMint}当成了字符串输出显示${LinuxMint}
简单讲就 双引号内是可以被执行的,单引号内是不执行的,原来是什么就显示什么
1 2 3 4 # 一个变量名字也可被另外一个变量当做值来使用 LinuxMint="123456" MY_ABC="${LinuxMint}" echo "${MY_ABC}" # 显示 123456
总结:双引号内是可以被执行的。单引号内是不执行的,原来是什么就显示什么。
[ cat ] 作用:读取文本件,不管是文本文件,还是二进制文件。 比如桌面有个文本文件 ABC.TXT 里面有456
1 cat /home/$USER/桌面/ABC.TXT 显示 456
比如 桌面 ABC.TXT 有4行 第一行 123 第二行 456 第三行 789 第四行 456
1 2 3 4 5 6 7 8 cat /home/$USER/桌面/ABC.TXT|wc -l 显示数字 4 表示有4行 cat /home/$USER/桌面/ABC.TXT|grep '456' 用来筛查一个文件件中的匹配 456 的所有行 显示包含456的行 这里有两行456 会显示两行456 cat /home/$USER/桌面/ABC.TXT|sed -n 1p 显示第一行 也就 123 ,sed -n 1p中的1p表示第一行 2p表示第二行 cat /home/$USER/桌面/ABC.TXT|grep '456'|sed -n 1p grep 匹配到 包含 456有两行,sed -n 1p 在显示过来出来的第一行
总结:cat 通常配置 wc 、grep 、sed 一起使用
[ sed ] sed 的用法很多这里举例一些我使用的。 把一个文件中包含特定的所有字符串替换成指定的,比如替换 IP地址 /home/$USER/桌面/ip.txt 有多处IP是一样的 192.168.5.1 替换成 192.168.5.5
1 sed -i -r "s|192.168.5.1|192.168.5.5|g" /home/$USER/桌面/ip.txt
获得网卡名字
显示如下 lo: 86428 726 0 0 0 0 0 0 6428 726 0 0 0 0 0 0 ens32: 36274552 317224 0 0 0 0 0 0 631688016 460301 0 0 0 0 0 0 docker0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
通过 grep 过滤特征字符串 ens enp wl这个是无线网卡 docker
1 2 3 4 5 6 7 8 9 10 11 12 13 grep 'ens' # 特征过滤没有会显示空行 grep 'enp' # 特征过滤没有会显示空行 grep 'docker' # 特征过滤没有会显示空行 grep 'wl' # 特征过滤没有会显示空行 awk '{print $2}' # 表示列$2表示第二列,$1表示第1列 cat /proc/net/dev|grep 'ens'|sed 's/^[ ]*//g'|sed 's@:[^ ]*@@g'|sed "s/ .*$//" # 我这显示 ens32 这个就是网卡名字,自动配置 .conkyrc 就用得上 ens32: 36274552 317224 0 0 0 0 0 0 631688016 460301 0 0 0 0 0 0 cat /proc/net/dev | grep 'ens'|awk '{print $2}' 最后特征字符串的行,显示第二列 就是36274552 # 这个用来判断使用的网卡是否有联网
总结:sed 是用来、删减、替换的
[ grep ] grep 是查找字符串的命令
1 2 3 4 5 ZiFuChuang='123' FileDir='/opt' grep -rEn "${ZiFuChuang}" "${FileDir}" | grep -v "Binary file" > $finddir/1.txt # 意思就是在/opt目录以及所有的子目录,直到最后一级目录里的文件,去找找包行 123的文件并且显示在哪一行出现 并且把得到的数据保存到 > 清空并保存$finddir/1.txt
注意事项:如果你不确定变量的直是否会被执行你一定要用单引号
[ `` ]单反引号 在英文输出法下按ESC下面那个键 单反引号必须成对使用,表示里面内容是可以执行的命令
1 2 3 4 5 6 7 8 9 10 # 有一个文件 name.log 里面有 3行数据 我想显示你好啊的那一行,已知在第二行 # 第一行 wewre # 第二行 你好啊 # 第二行 你好啊,你好啊 NAME_A=`cat ./name.log|sed -n 2p` echo "${NAME_H}" # 或者 ABCD_B=`cat ./name.log|grep '你好啊'|sed -n 1p` echo "${NAME_B}"
[ 自定义函数 ] 简单理解就是,执行一个函数就执行了函数里面的一大段代码,函数内的东西不影响函数外的东西
1 2 3 4 5 ABCD(){ echo '张三' } ABCD # 该ABCD表示执行,然后显示**张三**
函数也可以单做变量的直来使用:
1 2 3 echo "`ABCD`" >> ./123.txt # 打印执行后的行数结果追加到123.txt ZhangSan="`ABCD`" echo "${ZhangSan}" # 显示 张三
类似的一种写法,一般不建议这种写法,可以用来配合zenity很直观:
1 2 ZhangSan=$(echo '张三') echo "${ZhangSan}"
[ tee ] 主要是配合提权使用,这个可以用来修改系统配置文件 resolfconf 如果安装 docker 无法上网:
1 2 3 4 5 6 7 8 9 10 11 12 sudo apt-get install resolvconf -y echo 'nameserver 192.168.5.1' | sudo tee -a /etc/resolvconf/resolv.conf.d/base echo 'nameserver 114.114.114.114' | sudo tee -a /etc/resolvconf/resolv.conf.d/base echo 'nameserver 8.8.8.8' | sudo tee -a /etc/resolvconf/resolv.conf.d/base echo 'nameserver 192.168.5.1' | sudo tee -a /etc/resolvconf/resolv.conf.d/tail echo 'nameserver 114.114.114.114' | sudo tee -a /etc/resolvconf/resolv.conf.d/tail echo 'nameserver 8.8.8.8' | sudo tee -a /etc/resolvconf/resolv.conf.d/tail echo 'TRUNCATE_NAMESERVER_LIST_AFTER_LOOPBACK_ADDRESS=no' | sudo tee -a /etc/default/resolfconf sudo /etc/init.d/resolvconf restart sudo resolvconf -u sudo service networking restart sudo systemctl enable resolvconf.service
[ sleep ] 卡时间用的命令:
1 2 sleep # 后面加数字 最好是正数不能好似负数 sleep 3 # 表示等待3秒
在移动文件后使用更好:
1 2 3 4 5 6 7 # 单纯移动文件 mv /tmp/123 /home/$USER/桌面 # 移动重命名456 mv /tmp/123 /home/$USER/桌面/456 sleep 1
就是有些命令执行完以后为了保证安全性 需要等待多久时间以后在执行
[ 其他命令 ] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cd # 进入目录 cd /opt ls # 列出当前目录的文件不包含隐藏文件 ls /bin | grep 'terminal' | sed -n 1p # 找出终端名称 ls -a $HOME #显示家目录当前文件或文件夹包括.的隐藏 cp -r # 复制文件(不重命名) cp -r /opt/123.txt /home/$USER/桌面 cp -r # 复制文件(重命名) cp -r /opt/123.txt /home/$USER/桌面/456.txt mkdir # 创建文件夹 # 套娃创建法最里面一个文件夹是471 推荐 mkdir -p dir 这种 mkdir -p /home/$USER/桌面/456/789/471 chmod -R 750 file # 是加权限的
[ 常用判断逻辑 ] 1.两个变量的直是否相等 2.是否存在一个文件 3.是否存在一个文件夹 4.程序或命令执行与否,判断正常执行返回值 是 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 有一个文件 ABC.TXT 里面有两行 # 第一行 王五 # 第二行 李四 # 判断文件里面有没有张三,没有就写入一个张三 ZhangSan="1" # 肯定要假设存在一行 ZhangSan="1" NAME=`cat ./ABC.TXT|grep '张三'|wc -l` # 如果没有张三就是0行 if [ ! x${ZhangSan} = x${NAME} ];then # 如果不存在,上面肯定是没有的,所以执行这一段后,判断就结束了。 echo "张三" >> ./ABC.TXT else # 如果存在 echo "" exit fi
判断文件是否存在:
1 2 3 4 5 6 7 if [ ! -f /bin/zenity ];then # 不存在执行这里 sudo apt install -y zenity else # 存在执行这里 echo "zenity 已安装" fi
判断文件夹是否存在:
1 2 3 4 5 6 7 if [ ! -d /opt/123 ];then # 不存在执行这里 echo "1" else # 存在执行这里 echo "2" fi
程序或命令执行与否:
1 2 3 4 5 6 7 8 9 10 11 12 13 # 判断是否安装了docker 返回值是 0,就代表程序执行成功了 也就是安装了docker docker -v 2>/dev/null if [ $? -ne 0 ]; then # 不等于0执行这里 echo '你没有安装docker正在为你安装......' sudo apt install docker.io sudo usermod -aG docker $USER sudo systemctl daemon-reload sudo systemctl restart docker else # 等于0执行这里 echo '你已经安装了docker' fi
[ 截取字符串 ] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 path=ss/usr/share/src/root/home/admin/src/add echo $path echo ${path%src*} #从右向左截取第一个 src 后的字符串 echo ${path} echo ${path%/*}从右向左截取 第一个 / 后的字符串 echo ${path%%/*}从右向左截取 最后一个 / 后的字符串 echo ${path#*/}从左向右截取第一个 / 后的字符串 echo ${path##*/}从左向右截取最后一个 / 后的字符串 echo ${path:3} echo ${path:6:60}截取变量path从前三个字符串,表那一行第6个字符到第N个字符, echo ${#path}计算 path变量 一共有几个字符串 echo ${path/root/kyo}把path变量里的第一个root字符串,替换为 kyo字符串 echo ${path//s/m}把path变量里的所有的s字符,替换为 m 字符 echo ${path}
[ 把一大段东西保存到文本文件 ] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # 创建 桌面起动器文件为例 desktop_name='abc' Name='xxx' Exec_dir='/opt/123.sh' Icon_dir='/opt/i8520-SH/i8520Launcher.svg' cat > /home/$USER/桌面/${desktop_name}.desktop<<EOT [Desktop Entry] Name=${Name} Name[zh_CN]=${Name} Comment=${Name} Terminal=false Type=Application Categories=Graphics; StartupNotify=true Actions=Configure;Capture; Exec=${Exec_dir} Icon=${Icon_dir} EOT chmod -R 750 /home/$USER/桌面/${desktop_name}.desktop