终于撑到了 shell script
写在前面:
- 命令是自上而下,自左而右的
- 空格和空白行将被忽略
- 当读取到一个ENTER,就尝试执行该行命令
- 一行命令太多可以用 \enter 换行
- # 为注释
- 直接命令执行, shell.sh 文件必须有xr权限
- 绝对路径执行
- 相对路径执行
- 变量PATH, 写入脚本来执行
- 通过命令sh shell.sh <==> bash shell,sh 或 source shell.sh (这个命令跟前面的有差别, 后面说)
日上フブキ的第一个脚本:
mkdir bin;cd bin
vim hello.sh
#!/bin/bash
# 这是随便写的注释
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "Hello world! \a \n"
exit 0
关于上面脚本要BB的一些事情:
- 第一行的 #!/bin/bash 不是注释, 告诉系统,我这个bin下的文件是要是用的bash语法的,bin是可变的, 要根据所在位置变化
- # 就是注释
- PATH 说的是环境变量, 一般都这么配置。作用就是调用外部命令, 如在脚本里加 ll -a / 就能正常执行,否则没这个PATH, 会报错,说找不到ll 命令。这是因为配置好PATH, 就可以直接用外部命令了, 而不用写下它绝对路径引用。总之一句话,就是要写这个PATH
- 返回值, exit退出 返回0, 说明程序正常执行
- 执行时, 直接在当前目录 sh.hello.sh
下一个脚本, 能与用户交互
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "input your fname" fname
read -p "input your lname" lname
echo -e "\n Your name is ${fname} ${lname}"
下面根据日期创建文件名
${filesuer:-"filename"} 相当给一个默认名, filesuer为空即用户输入为空时,用filename
date1=$(date --date='2 days ago' +%Y%m%d) 最坑的是这个,'2 days ago‘ 用单引号, +%Y%m%d 这个+一定要和前面的有个空格
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "input your filename" fileuser
filename=${filesuer:-"filename"}
date1=$(date --date='2 days ago' +%Y%m%d)
date2=$(date --date='1 days ago' +%Y%m%d)
date3=$(date +%Y%m%d)
file1=${filename}${date1}
file2=${filename}${date2}
file3=${filename}${date3}
touch "${file1}"
touch "${file2}"
touch "${file3}"
下面利用$(()) 进行简单的数值计算, 默认只支持整数
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "input 2 num \n"
read -p "first num" fnum
read -p "second num" snum
total=$((${fnum}*${snum}))
echo -e "\n ${total}"
下面稍微改动下,能支持小数计算了, 加了个bc
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "input 2 num \n"
read -p "first num" fnum
read -p "second num" snum
echo -e "\n ((${fnum}*${snum}))" | bc
下面说说,启动脚本命令sh 和 source 的区别
1 sh命令是bash 的别名, 使用它, 相当于开启了一个新的子进程,开启一个新的bash环境,重点在于,子进程完成后,在子进程内的各项变量或操作将会结束而不会回传到父进程中。就是说,用sh开启个脚本, 运行完, 回到父进程,在调用脚本变量,是不能调过来的。
2 source 来执行脚本, 是在父进程中来执行脚本的, 可以用脚本里的变量。
有些nb的test命令
-e | 文件名是否存在 |
-f | 改文件名是不是文件 |
-d | 改文件名是不是目录 |
-r | 文件名是不是有可读权限 |
-w | 文件名是不是又有写入权限 |
-x | 文件名是不是有可执行权限 |
-u | 有没有suid权限 |
-g | 有没有sgid权限 |
-k | 有没有sticky bit 权限 |
-s | 是不是空文件夹 |
下面 | test file1 -nt file2 |
-nt | 后面接两个文件, 判断文件1是不是比文件2新 |
-ot | 1是不是比2旧 |
-ef | 1和2 是不是同样一个文件夹 |
下面 | test n1 -eq n2 n1 和n2 是两个整数 |
-eq | 两个数是不是相等 |
-ne | 两个数不相等 |
-gt | n1 大于 n2 |
-lt | n1 小于 n2 |
-ge | n1 大于等于 n2 |
-le | n1 小于等于 n2 |
test -z string | 判断字符串是否为0?若为空, 返回True |
test -n string | 字符串为空, 返回False |
test str1 == str2 | 两个字符串是不是相等 |
test str1 != str2 | 是不是不相等 |
下面 | 多重条件判断 |
-a | test -r filename -a -x filename -a 是and |
-o | 是or |
! | 不等于 |
test -e /xx 判断xx存不存在 直接执行不会显示任何结果
test -e /xx && echo "exit" || echo "not exit"
小例子
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "input a filename, I will check the filename's type and permission. \n\n"
read -p "input a filename" filename
test -z ${filename} && echo "you must input filename" && exit 0
test ! -e ${filename} && echo "the filename '${filename}' is not exit " && exit 0
test -f ${filename} && filetype="reg"
test -d ${filename} && filetype="dir"
test -r ${filename} && perm="r"
test -w ${filename} && perm="${perm} w"
test -x ${filename} && perm="${perm} x"
echo "the filename: ${filename} is a ${filetype}"
echo "and per is ${perm}"
上面的test也可用[]
[ -z "${HOME}" ] ; echo $?
千万注意!!!!
[空格 -z "{HOME}"空格] [空格"$HOME"空格==空格"$MALL"空格] [] 两边得有空格, 里面的组件也要有空格
- 中括号内的每个组件都需要有空格
- 中括号的变量最好用双引号括起来
- 中括号内的常数最好用单引号或双引号括起来
- 小demo
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "please input (Y/N)" yn
[ "${yn}" == "Y" -o "${yn}" == "y" ] && echo "ok" && exit 0
[ "${yn}" == "N" -o "${yn}" == "n" ] && echo "fuck it" && exit 0
echo "i don't know what your choice" && exit 0
shell script 的默认变量
sh hello.sh opt1 opt2 opt3 opt4
$0 $1 $2 $3 &4
脚本的名字是 第零个变量 $0 , $1 第一个变量 。。。。
$# | 代表参数的个数,不含$0, 本例是4 |
$@ | ["$1" "$2" "$3" "$4"] 记这个 |
$* | ["$1c$2c$3c$4"] c是分割符, 默认是空格 |
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo "the script name is${0}"
echo "total paramether number is $#"
[ "$#" -lt 2 ] && echo "the number of parameter is less then 2. stop" && exit 0
echo "your whole parameter is $@"
echo "${1}"
echo "${2}"
输入 xx.ch 1 2 3 4
还有个 shift 偏移变量
&{1} --> 1
shift 2 去掉前两个变量
&{1} --> 3
条件判断式
1 if then
if [条件判断]; then
条件成立时,执行
fi 结束if判断
if [条件判断]; then
条件成立时,执行
else
条件成立时,执行
fi 结束if判断
if [条件判断]; then
条件成立时,执行
elif [条件判断];then
条件成立时,执行
else
条件成立时,执行
fi 结束if判断
[ "${yn}" == "Y" -or "${yn}" == "y" ]
等价于
[ "${yn}" == "Y" ] || [ "${yn}" == "y" ]
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "input" yn
if [ "${yn}" == "y" ] or [ "${yn}" == "Y" ]; then
echo "ok"
exit 0
fi
2 利用case esac
case $变量 in
"第一个变量的内容")
程序段
;;
"第二个变量的内容")
程序段
;;
*)
不包含第一个和第二个变量的内容执行此处
exit 1
;;
esac
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
case ${1} in
"hello")
echo "hello "
;;
"")
echo "please input"
;;
*)
echo "fuck it"
;;
esac
利用function 功能
shell script 中的function 必须写在程序的前面。
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
function printit() {
echo -n "your choice is ${1}" # ${1} 是这个行数的第一个参数
}
case ${1} in
"one")
printit 1
;;
"two")
printit 2
;;
"three")
printit 3
;;
*)
echo "user ${0} {one|two|three}"
;;
esac
不定循环
while do done
当condition 成立时一直执行
while [ condition ]
do
xxxxxx
done
untile do done
当condition 成立时退出循环
until [ condition ]
do
xxxx
done
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
s=0
i=0
while [ "${i}" != "100" ]
do
i=$(($i+1))
s=$(($s+$i))
done
echo "the result is $s"
固定循环
for do done
for var in con1 con2 con3
do
xxxx
done
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
for i in aki desky enako
do
echo "${i}"
done
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
users=$(cut -d ':' -f1 /etc/passwd)
for i in ${users}
do
id ${i}
done
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
network="192.168.1"
for i in $(seq 1 100)
do
xxx
done
想说的就是 $(seq 1 100), 1到100
for do done 的数值处理
for ((初始值; 限制值; 赋值运算;))
do
xxx
done
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "input a num " nu
s=0
for (( i=1; i<=${nu}; i=i+1 ))
do
s=$((${s}+${i}))
done
echo "result ${s}"
shell 脚本的跟踪和调试
sh
-n 不要执行脚本, 仅查语法问题
-v 在执行脚本前, 先将脚本的文件内容写在屏幕上
-x 将使用的脚本内容显示到屏幕上
sh -n hello.sh 语法没问题, 无任何显示