- 推荐网站:Advanced Bash-Scripting Guide
- mkdir shellscript&&cd shellscript
- vim hello
- 开头以#! /bin/bash来标识文件使用bash来运行的
- 输入 echo ‘hello world’
- ll 显示没有user的执行权限
- chmod u+x myown 改变权限,文件会变颜色,后面加上一个可执行文件的星号
- ./hello 就可以执行脚本了
#!/bin/bash
echo "Please type first number:"
read param1
echo "Please type second number"
read param2
result=$[$param1+$param2]
echo "The result is :"$result
或者
#!/bin/bash
echo "first: $1" # 大于10的参数用 ${10} 来表示
echo "second: $2"
sum=$[$1+$2]
echo "result: $sum"
echo "the script name is $0" # $0是程序名,包含路径
echo 'basename $0' # basename输出的不包含路径
# 输入./add 3 5 自动定位到变量,
- if [ -f file ] 如果文件存在
- if [ -d … ] 如果目录存在
- if [ -s file ] 如果文件存在且非空
- if [ -r file ] 如果文件存在且可读
- if [ -w file ] 如果文件存在且可写
- if [ -x file ] 如果文件存在且可执行
- if [ int1 -eq int2 ] 如果int1等于int2
- if [ int1 -ne int2 ] 如果不等于
- if [ int1 -ge int2 ] 如果>=
- if [ int1 -gt int2 ] 如果>
- if [ int1 -le int2 ] 如果<=
- if [ int1 -lt int2 ] 如果<
- if [ a= b ] 如果string1等于string2 字符串允许使用赋值号做等号
- if [ string1!= string2 ] 如果string1不等于string2
- if [ -n $string ] 如果string 非空(非0),返回0(true)
- if [ -z $string ] 如果string 为空
- if [ $sting ] 如果string 非空,返回0 (和-n类似)
if condition1
then
command1
elif condition2
command2
else
commandN
fi
# 下面是实例
num1=$[2*3]
num2=$[1+5]
if test $[num1] -eq $[num2]
then
echo '两个数字相等!'
else
echo '两个数字不相等!'
fi
#! /bin/bash
function func1 {
echo 'this my first function'
}
func1 # 定义之后才能调用
func2() {
echo 'This is another function'
return 20
}
func2
echo "$?" # 必须在函数执行后立即执行,对退出状态码进行访问,必须在0-255,没有return时默认正确是0,不成功是其他
value=`func1` # 将func1的输出赋值给value,这里是用的反引号,命令替换是指shell能够将一个命令的标准输出插在一个命令行中任何位置
echo "$value"
#! /bin/bash
add() {
if [ $# -eq 2 ];then
result=$[ $1+$2 ]
echo $result
else
echo "Please input 2 params"
return 1
fi
}
value=`add $1 $2` # 函数的echo会返回到这里
if [ $? -eq 0 ]; then # 判断退出码
echo $value
else
echo "Err: $value"
fi
#! /bin/bash
testarray(){
echo "$@"
echo "$1"
echo "$2"
echo "$#"
}
sum(){
local result=0 # 不加local是全局变量
for var in $@
do
result=$[ $result + $var ]
done
echo $result
local newarray=(`echo "$@"`)
echo ${newarray[*]} # 返回数组
}
array=(1 2 3 4 5 6 7)
testary $array # 这里只传进去了第一个参数
testary ${array[*]} # 将数组当成了7个参数传了进去
sum ${array[*]}
echo "This is outside function: $result" # 此时访问不到了
# /calc.sh 函数库文件,加.sh是为了更方便的查找脚本,可以不加
#! /bin/bash
add() {
local result=0
if [ $# -eq 2 ]; then
result=$[ $1 + $2 ]
echo $result
else
echo 'Need 2 number params'
return 1
fi
}
sum(){
local result=0
for var in $@
do
result=$[ $result + $var ]
done
echo $result
}
# /test4 测试文件
#! /bin/bash
source ./calc.sh # 将已知文件引入到当前环境
echo `add 12 23`
- vim ~/.bashrc
- 在最后添加 . ~/shellscript/calc.sh
- expr length “hello” 字符串长度
- expr length “$str” 参数是变量
- expr index “$str” ‘h’ 查找h在str中的位置,返回第一个匹配的位置
- bc 进入bc工具
- bc -q 不显示欢迎条
- scale=4
- 100/3 结果是33.3333,不设置scale会是33
- quit 退出 scale会失效,每次都要设置
- num2=3;num3=17 # 自定以变量,要以分号间隔
- var=
echo "options;expression" | bc
# 反引号 在脚本中引用bc- var=’echo “scale=4;3.44/5” | bc’
var1=10.46
var2=43.67
var3=33.2
var4=71
result=`bc << EOF # << 内联输入重定向,EOF开始和结束的标识符,可以自定义
scale=4
a1 = $var1 * $var2
b1 = $var3 * $var4
a1+b1
EOF
` # 反引号 EOF 进行重定向
echo result
#! /bin/bash
for val in Jan Feb Mar Apr May # 列表循环
do
echo "Month name is $val"
done
list="Jan Feb Mar Apr May"
for val in $list # 使用变量实现循环
do
echo "Month name is $val in list"
done
IFS=$";" # 修改分隔符为;且只有;
for var in `cat datefile` # 文件读入,默认分隔符是空格,换行,制表符
do
echo "Month name is $val in file"
done
for var in ~/shellscript/* # 也可以是c* # 可以直接读取文件列表,一定要加通配符
do # 等同于 for var in `ls ~/shellscript/*`
echo "$var"
done
for((i=1,j=10;i<=10;i++,j--)) # 类C的结构
do
echo "test number is $i $j"
done
var=1
while [ $var -lt 10 ] # command写成[]的形式
do
echo "$var"
var=$[ $var+1 ] # expression 写成$[]的形式
done
var=1
while [ $var -en 10 ] # command写成[]的形式
do
echo "$var"
var=$[ $var+1 ] # expression 写成$[]的形式
done
#! /bin/bash
exec 1>testoupt # 这里就把整个脚本的输出都定向了
exec 2>errlog
echo "test error" >&2 # 错误信息还需要临时重定向
echo "normal output 1"
echo "normal output 2"
#! /bin/bash
exec 0< errlog
count=1
while raed line
do
echo "line #$count : $line"
count=$[ $count+1 ]
done
#! /bin/bash
if [ $# -lt 2 ] # $#参数计数, -lt 小于
then
echo 'Please input at least 2 param'
exit
fi
name=`basename $0`
if [ $name = "add" ]
then
result=$[ $1 + $2 ]
elif [ $name = "minus" ]
then
result=$[ $1 - $2 ]
fi
echo "The $name result is $result "
# ln -s calc add&&ln -s calc minus 进行软连接
#! /bin/bash
echo $# # 统计参数个数
echo $* # 所有变量作为一个参数
echo $@ # 变量存进列表
for var in "$*"
do
echo "\$* Param = $var"
done
for var in "$@"
do
echo "\$@ Param = $var"
done
#! /bin/bash
result=0
while [ -n "$1" ] # -n表示非空
do
result=$[ $result + $1 ]
shift # 位置参数的值会减1,都向前移动一位
done
echo "SUM of numbers is : $result"
- 上面的命令会输出:-b value -a -c -d – param1 param2
- getopt不能解决value中带有空格的,要用getopts
# 输入 ./test2 -ac -b value param1 param2
#! /bin/bash
set -- `getopt -q ab:c "$@"` # set -- 是将getopt的结果重新付给命令行参数 -q 不会输入遇到的错误
while [ -n "$1" ]
do
case "$1" in
-a) echo 'Option -a' ;;
-b) value="$2"
echo "Option -b ,Value is : $value" # $要写到双引号里
shift;; # 因为读了一次值,要shift一次
-c) echo 'Option -c' ;;
--) shift # 当不是选项,是参数是执行,下面可以写函数体
break;;
esac
shift
done
echo "Params are : $*"
# 输入 ./test3 -ac -b "value 123" "param1 123" param2
#! /bin/bash
while getopts ab:c opt # 会把所有解析出来的参数放到opt中
do
case "$opt" in
a) echo 'Option -a' ;;
b) echo "Option -b ,Value is : $OPTARG" ;; # 选项的值会放到$OPTARG中
c) echo 'Option -c' ;;
*) echo "Unknown option: $opt" ;;
esac
done
shift $[ $OPTIND -1 ] # $OPTIND存放解析的选项的数量,后面就只剩参数部分了
count=1
for param in "$@"
do
echo "Param #$count is: $param"
count=$[ $count + 1 ]
done
#! /bin/bash
if read -t 5 -p "Please type your input:" input # -t 5秒为超时,-p 输入提示
then
echo "You typed: $input"
else
echo "Timeout"
fi
#! /bin/bash
echo "Please input a password:"
read -s passwd
echo
echo "Your password is : $passwd"
#! /bin/bash
exec 0< read_test1
count=1
while read line
do
echo "#$count: $line"
count=$[ $count + 1 ]
done
- 利用管道来实现
#! /bin/bash
count=1
cat read_test1 | while read line
do
echo "#$count: $line"
count=$[ $count + 1 ]
done
- 组合键产生信号
- Ctrl + C 终止进程 SIGINT
- Ctrl + Z 暂停进程 SIGSTP
- ping www.baidu.com
- Ctrl + Z
- ps -ef | grep ping # 可以看到ping命令还在执行中
- 命令产生信号 kill、killall
- ps # 查看当前的进程
- kill -9 25949 # -9是无条件终止,25949是ps命令查出来的PID
- ps # 刚放的进程已经被终止
#!/bin/bash
trap "echo 'Signal traped SIGINT for Ctrl+C'" SIGINT # 改变Ctrl + C为 输出文本
trap "echo 'quit script'" EXIT # 捕捉退出命令,并修改
count=1
while [ $count -le 10 ]
do
echo "Loop # $count"
sleep 1 # 1秒钟的休眠
count=$[ $count + 1 ]
done
trap - EXIT # 移除添加的trap,不会再输出quit script
echo 'Loop ended'
# 只需要输入 ./bgtest &
# nice -n 10 ./bgtest > temp & 后台运行脚本,优先级10(最高-20,最低19)
# renice 10 -p 19863 通过PID来修改进程的优先级
# ps al 可以查看进程优先级,普通用户只能最高设置到0
# nohup ./bgtest & 使脚本的运行与bash无关,可以关掉bash,默认输出到nohup.out
#!/bin/bash
trap "echo 'quit script'" EXIT
count=1
while [ $count -le 10 ]
do
echo "Loop # $count"
sleep 5
count=$[ $count + 1 ]
done
trap - EXIT
echo 'Loop ended'
- Ubuntu默认没有at命令,sudo apt-get install at
- at 默认是以邮件的形式发送到指定的邮箱,所以脚本开头有一个标准输出重定向
# at -M -f ./attest 18:18 M参数指的是不用邮箱,f参数是运行脚本
# at -M -f ./attest now+2 min
# atq 会看到at的运行队列
# atrm 12 通过PID来删除at作业
#!/bin/bash
exec 1>>atresult
echo "script run at `date`"
echo "end scritp"
- 不同系统启动运行不同,主要有一下两种
- System V init
- Upstart init
- 自定义开机运行脚本
- debian /etc/init.d/rc.local
- Ubuntu /etc/rc.local
- openSUSE /etc/init.d/boot.local
- CentOS /etc/rc.d/rc.local
- 在Ubuntu中
- vim /etc/rc.local 最开始添加调试功能
- exec 1>>/home/helloworld/logs/startup/logs
- exec 2>>/home/helloworld/logs/startup/error
- 后面输入脚本的路径就行了,环境变量要放到另外的脚本,然后引入
- 启动shell的三种方式
- 启动bash
- 通过ssh登陆
- 通过ssh执行命令 直接执行,不会login shell,在man ssh中可以查到
- 因此,使用ssh执行命令,不会调用/etc/profile指定的设置,只调用/etc/.bashrc这个文件
- 下面是各种启动shell时调用的文件
- 启动bash /etc/profile /etc/.bashrc
- 通过ssh登陆 /etc/profile /etc/.bashrc
- 通过ssh执行命令 /etc/.bashrc
- vim /etc/crontab 查看cron时效表格式
- ls /etc/cron* 查看更多的信息,可以添加自己的脚本到指定的文件夹下
- crontab -l 显示当前用户的时间表
- crontab -e 修改用户时间表
- 缺点是默认电脑是7*24小时都开机的,可以用anacron
- vim /etc/anacrontab 查看格式,最小配置是1天1次
- SSH免密码登录
- 实现ssh自动登录的4种方法
- A为本地主机(即用于控制其他主机的机器),B为远程主机(即被控制的机器Server), 假如ip为192.168.56.101,A和B的系统都是Linux
- 在A上的命令:
ssh-keygen -t rsa (连续三次回车,即在本地生成了公钥和私钥,不设置密码)
ssh root@192.168.56.101 "mkdir .ssh;chmod 0700 .ssh" (需要输入服务器root密码, 注:必须将.ssh的权限设为700)
scp ~/.ssh/id_rsa.pub root@192.168.56.101:.ssh/id_rsa.pub (需要输入服务器root密码)
- 在B上的命令:
touch /root/.ssh/authorized_keys (如果已经存在这个文件, 跳过这条)
chmod 600 ~/.ssh/authorized_keys (# 注意: 必须将~/.ssh/authorized_keys的权限改为600, 该文件用于保存ssh客户端生成的公钥,可以修改服务器的ssh服务端配置文件/etc/ssh/sshd_config来指定其他文件名)
cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys (将id_rsa.pub的内容追加到 authorized_keys 中, 注意不要用 > ,否则会清空原有的内容,使其他人无法使用原有的密钥登录)
- 也可以把Key放到其他的用户的文件里实现无密码登录,如:ssh [email protected] “mkdir .ssh;chmod 0700 .ssh”
- 回到A机器: ssh [email protected] (不需要密码, 登录成功)
- 假如在生成密钥对的时候指定了其他文件名(或者需要控制N台机器,此时你会生成多对密钥),则需要使用参数-i指定私钥文件
- ssh [email protected] -i /path/to/your_id_rsa
- scp也是一样,如:
- scp -i /root/.ssh/id_rsa ./xxx 192.168.102.158:/home/wwy/bak
- 因为默认情况下ssh命令会使用~/.ssh/id_rsa作为私钥文件进行登录,如果需要连接多台服务器而又不希望每次使用ssh命令时指定私钥文件,可以在ssh的客户端全局配置文件/etc/ssh/ssh_config(或本地配置文件~/.ssh/config, 如果该文件不存在则建立一份)中增加如下配置
- IdentityFile /path/to/your_id_rsa.
- 也可以为每个服务器指定一个Host配置:
- Host 192.168.56.101
- IdentityFile /path/to/your_id_rsa
- 如果连接时出现如下的错误:Agent admitted failure to sign using the key
- 则使用 ssh-add 指令將私鑰 加進來 (根据个人的密匙命名不同更改 id_rsa):
- ssh-add ~/.ssh/id_rsa
- sudo apt-get install sshpass
- 安装完成后使用sshpass允许你用 -p 参数指定明文密码,然后直接登录远程服务器。例如:
- sshpass -p ‘你的密码’ ssh 用户名@服务器ip地址
- 用 ‘-p’ 指定了密码后,还需要在后面跟上标准的 ssh 连接命令。
- sshd的配置文件/etc/ssh/ssd_config
- 可以设置为免密码登录,不推荐