一、shell script 编程模板
#!/bin/bash
#通常用作注释,但是#!放在一起是一个特殊的表示符,标志着这是一个shell script,其后的路径指出了用来解释这个script的程序位置。
bash只是shell的一种,还有很多其它shell,如:sh,csh,ksh,tcsh,...
#!/bin/bash只能放在第一行,不在第一行的#!/bin/bash,只是一个注释。
#!/bin/sh
表示用 Bourne shell 来执行.
如果系统中没有 sh, 会选择兼容的 shell 解释器
#!/bin/bash
表示用 Bash shell 来执行
如果系统中没有 bash, 会选择兼容的 shell 解释器
变量赋值
# $0 代表被调用者自身的名字
# $1 代表第一个参数,$N 代表第 N 个参数
# $# 代表参数个数
# $@ 代表所有参数,类型是个数组,想传递所有参数给其他命令用 cmd "$@"
# $* 空格链接起来的所有参数,类型是字符串
arg1=$1 # 获取命令行输入参数,或单引号
file_path="/tmp/test.txt" # 常量赋值
count=$(ls /tmp | wc -l) # 获取命令执行结果
count=`ls /tmp | wc -l` # 获取命令执行结果
size=`wc -c /tmp/a.txt | awk '{print $1}'`
size=`echo "scale=3; $size/$((1024**3))" | bc`
echo $size'GB'
current_script_path=$(readlink -f "$0") # 获取当前脚本路径
current_script_dir=$(dirname $(readlink -f "$0")) # 获取当前脚本所在目录
root=$(pwd)
path=/home/a.txt
a=$(basename $path) # a.txt
a=`basename $path`
a=$(basename $path .txt).json # a.json
四则运算 expr,let,bc,(())
# expr命令是一个手工命令行计数器,用于在UNIX/LINUX下求表达式变量的值,一般用于整数值,也可用于字符串,不支持浮点除法
a=`expr 1 + 2`
a=$(expr 1 - 2)
a=$(expr 2 \* 3) # 使用乘号时,必须用反斜线屏蔽其特定含义
a=$(expr 4 / 2)
# let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。
let a=1+2
let a=1-2
let a=2*3
let a=4/2
let a=(1+2)*3
# bc 命令是任意精度计算器语言,通常在linux下当计算器用
a=`echo "1+2" | bc`
a=`echo "1-2" | bc`
a=`echo "2*3" | bc`
a=`echo "4/2" | bc`
a=`echo "(1+2)*3" | bc`
a=`echo "10^2" | bc`
a=`echo "scale=2; 0.5/2" | bc` # 浮点除法
# (()) 的用法
a=$((1+2))
a=$((1-2))
a=$((2*3))
a=$((4/2))
a=$(((1+2)*3))
#自增加1
((a++))
let a++ #let a+=1
a=`expr $a + 1`
a=$[$a+1]
a=$(($a+1))
判断
#!/bin/bash
#判断后缀
file=$1
extension="${file##*.}"
if [ ! "$1" ] || [ "$extension" != "txt" ]; then
echo "eg. bash ./test.sh a.txt"
exit 1
elif [ ${file:0:1} = "A" ]; then
echo "begin with 'A', skip"
else
echo "pass"
fi
#判断目录是否存在
dir=$1
if [ ! -d "$dir" ]; then
mkdir $dir
root="."
fi
#判断文件是否存在
file=$1
if [ -f "$file" ]; then
rm $file
fi
循环
1、逐行读取文件的3种方法:
方法1:while循环中执行效率最高,最常用的方法。
while read line
do
if [ ${line:0:1} = "#" ]; then
continue
fi
echo $line
done < $1
方法2:管道法
cat filename | while read line
do
echo $line
done
方法3:for 循环
for line in `cat filename`
do
echo ${line}
done
2、定时处理
#!/bin/bash
a=0
while true; do # while [ 1 ]
((a++))
echo -ne "$a\r" #不换行刷新数据
sleep 3s
done
sleep 1 睡眠1秒
sleep 1s 睡眠1秒
sleep 1m 睡眠1分
sleep 1h 睡眠1小时
输出
a='alan'
b=1314
d='1'
echo ${a}${b}"c"$(expr $d - 1)
echo "${a}${b}c$(expr $d - 1)"
echo -ne "$a\r" #不换行刷新数据
参数:
-n 不输出最后的\n,不自动换行
-e 若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:
\r 光标移至行首,但不换行
\t 插入tab
\n 换行且光标移至行首
\\ 插入\字符
\v或\f 换行但光标仍旧停留在原来的位置;
printf [format] [文本1] [文本2] ..
printf "%s %s %s\n" 1 2 3 4
printf " (%.2f) " 1 2 3 4
printf "%X" 10 #10进制转16进制
printf "%d" 0xA #16进制转10进制
printf "%-10s %-10s %-4s \n" 姓名 性别 年龄 小明 男 20 小花 女 18 #"-"表示左对齐, "10 10 4" 表示占的字符位数, 不够不空格
常用格式替换符
%s |
字符串 |
%f |
浮点格式 |
%d,%i |
十进制整数 |
%o |
八进制值 |
%x |
十六进制值(a-f) |
%X |
十六进制值(A-F) |
%% |
表示%本身 |
常用转义字符
\n |
换行 |
\t |
水平制表符 |
\\ |
表示\本身 |
文件描述符&输出重定向
在Linux系统中0 1 2是一个文件描述符
0表示标准输入(stdin)
1表示标准输出(stdout)
2表示标准错误输出(stderr)
> 默认为标准输出重定向,与 1> 相同
2> 标准错误输出重定向
2>&1 意思是把标准错误输出重定向到标准输出
&>file 意思是把标准输出和标准错误输出都重定向到文件file中
/dev/null是一个文件,这个文件比较特殊,所有传给它的东西它都丢弃掉,就像一个无底洞。
ls /tmp > /dev/null 2>&1 # 默认情况是1,也就是等同于1> /dev/null 2>&1。意思就是把标准输出重定向到“黑洞”,还把错误输出2重定向到标准输出1,也就是标准输出和错误输出都进了”黑洞“
ls /tmp 2>&1 >/dev/null # 意思就是把错误输出2重定向到标准输出1,也就是屏幕,标准输出进了“黑洞”,也就是标准输出进了黑洞,错误输出打印到屏幕
分割字符
OLD_IFS="$IFS"
IFS="," # 按逗号分割string,默认按空格分割
array=($string)
IFS="$OLD_IFS"
echo ${array[-1]} # 数组的最后一个数
for var in ${array[@]} # @表示取数组的所有数值
do
echo $var
done
字符串截取(分离文件名和后缀)
#!/bin/bash
FILE="example.tar.gz"
echo "${FILE%%.*}" # example --> (%%号是运算符,.* 表示从右边开始删除最后一个.号及右边的所有字符)
echo "${FILE%.*}" # example.tar --> (%号是运算符,.* 表示从右边开始删除第一个.号及右边的所有字符)
echo "${FILE#*.}" # tar.gz --> (#号是运算符,*. 表示从左边开始删除第一个.号及左边的所有字符)
echo "${FILE##*.}" # gz --> (##号是运算符,*. 表示从左边开始删除最后一个.号及左边的所有字符)
filename="${FILE%.*}"
extension="${FILE##*.}"
echo ${FILE:0:5} # examp --> 从左边第几个字符开始,及字符的个数
echo ${FILE:2} # ample.tar.gz --> 从左边第几个字符开始,一直到结束
echo ${FILE:0-6:3} # tar --> 从右边第几个字符开始,及字符的个数
echo ${FILE:0-1} # z --> 从右边第几个字符开始,一直到结束
# 注:(左边的第一个字符是用 0 表示,右边的第一个字符用 0-1 表示)
二、常用shell命令
ls | wc -l # 计算当前目录下的文件数
ls /tmp | grep "*.txt" | wc -l # 计算/tmp下txt文件的个数
cat a.txt | wc -l # 计算文件的行数
df -h # 查看磁盘使用情况
du -sh * # 查看当前目录下文件大小
将文件夹下的文件名存到文本中(提取 image 文件夹下所有图像序列的名字,按顺序保存为时间戳)
find image_dir -name "*.jpg" -printf "%f\n" > image_dir/timestamps.txt
sed -i -e 's/.jpg//g' image_dir/timestamps.txt
sort image_dir/timestamps.txt -o image_dir/timestamps.txt // 默认升序
找到后台程序进程号、杀掉进程、重启
ps -aux | grep <exe_name>
kill -9 <process_id>
nohup <exe_name> > out.log &
tail -f out.log
ps aux | grep <exe_name> | grep -v grep | awk '{print $2}' | sudo xargs kill -9
文本处理:
仅保存指定列满足条件的行
保留指定列
按指定列排序
awk '{print $2}' | awk -F: '{print $NF}'
awk -F " " '{print val$4}' val="$a"
sudo du -h --max-depth 1 查看当前文件夹下一级目录的大小
awk -F '_' '$4>3&&$4<4{print}' a.txt >> b.txt # 取a.txt中以"_"分隔满足条件的列,追加在b.txt中
sort -t_ -k1.2,1.2 -k4,4 a.txt -o b.txt # 对a.txt中以"_"作为分隔符,按第1列第2个字符排序,若相同,再按第四列排序,保存在b.txt中
cat a.txt | cut -d '_' -f 1 > b.txt # 取a.txt中以"_"分隔的第1列,保存在b.txt中
sort -u -r # 降序、不重复
find image_dir -name "*.jpg" -printf "%f\n" > image_dir/timestamps.txt
sed -i -e 's/.jpg//g' image_dir/timestamps.txt
sed -i '/xxx/d' filename # 删除包含"xxx"的行,原地操作
ls -lh
sed -n 指定行数;-n '2p':第二行;-n '1,3p':第一至三行
mkdir -p ${root}/{dir1,dir2}
set -e #在"set -e"之后出现的代码,一旦出现了返回值非零,整个脚本就会立即退出,那么就可以避免一些脚本的危险操作。
遍历文件夹下所有jar包文件,拷贝到目标目录中
find . -name "*.jar" | xargs -i cp {} /dir
cp后面的{}会被替换成xargs的输入
查找文件夹(包括子文件夹)下包含关键字的行及其所在的文件:
grep foo * -R
<other output> | grep "foo*"