环境: Centos 7 bash
终端打印命令
命令格式:
echo "String"/'String'/String
在屏幕上打印string
相比于echo,printf能适应格式化输出,与C中的printf相似
命令格式:
printf "strFormat" string1 string2 ...stringn
//示例
printf "%-5s %-10s %-4s\n" no name mark
printf "%-6.4f\n" 2.1
“-5s”:
‘-‘表示左对齐,默认为右对齐
5代表在屏幕上显示的列数。5.0表示数字类型时,如果数字的位数不够5,则使用0填充
s代表要输出的数据类型
s:字符串类型
d:整数类型
f:浮点数类型
当一个应用程序在执行时,它接受一组环境变量,可以使用env命令进行查看。对于每一个进程,其运行时的环境变量可以使用以下命令查看$PID表示进程的id
cat /proc/$PID/environ
var=value 变量赋值,如果value中存在空格,则需要使用引号
var = value 判断变量相等
var=sssss
echo $var
echo ${var}
echo var #错误
echo "we hava many ${var} m"
环境变量:未在当前进程中定义,从父进程继承而来的变量
//例如HTTP_PROXY
echo HTTP_PROXY
export HTTP_pROXY
linux提供了许多标准的环境变量,比如$PATH
echo $PATh
#输出 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
# 各目录路径之间使用:分割。给出命令之后,linux将会在各个目录中搜索指定命令名称的可执行文件
# 添加新的路径至$PATH
#'=' 两边没有空格
export $PATH="$PATH:/fullPATH"
var=value
len=${#var}
echo $len
# way 1
echo $SHELL
#way 2
echo $0
if [$UID -ne 0]; then
echo not a root user
else
echo "root user"
fi
在bash环境中,可以利用let,(()),[]执行基本的运算,expr和bc可以进行高级运算
var1=10
var2=30
let result=var1+var2
echo result # 40
#let支持++/--和简写模式
let var1++
let var1--
let var1+=10
let var1-=10
let var1/=2
let var1*=2
#[]命令与let相似
result=$[var1 + var2]
result=$[$var1 + var2]
#(())使用与[]相似
result=$(($var1 + 10))
result=$((var1 + 10))
# expr
result=`expr 3 + 4`
result=$(expr $var1 + 10)
# 命令格式
echo "4*0.15" | b`
bc命令的参数可以置于要执行的具体操作之前,使用;进行分割
#设置数值精度
echo "scale=2;3/8" | bc
#进制转换
echo "obase=2;16" | bc #结果 10000
echo "obase=10;ibase=2;1000" | bc #结果 8
#计算平方/平方根
echo "sqrt(100)" | bc
echo "10^2" | bc
0 stdin 标准输入
1 stdout 标准输出
2 stderr 标准错误
#输出重定向
echo "i am a boy" > temp.txt #清空原文件,然后写入
echo "i am a boy" >> temp.txt #在源文件末追加
#tee命令 将输入输出到标准输出,并且输出到指定的文件中
echo "meaningless string" > temp.txt
cat temp.txt | tee temp.back.txt | cat
#将脚本中的文本输出到文件中(下面的例子为一个shell脚本文件内容)
#!/bin/bash
cat <log.txt
line 1
line 2
line 3
EOF
cat log.txt #将会输出line 1\n line 2\n line 3\n
文件打开方式有三种,只读\截断\追加
可以使用命令exec创建自定义文件描述符
< 将文件内容读入stdin
> 截断模式写入文件,原文件内容被删除
>> 追加模式写入文件,数据被写在文件的尾部
exec 3
#查找当前目录以及子目录下所有的txt文件,并且找出含有‘bin’的行
find ./ -name "*.txt" -exec grep "bin" {} \;
#删除当前目录以及子目录下所有的txt文件
find ./ -name "*.txt" -exec rm {} \;
#定义
array=(1,2,3,4,5)
#输出
echo ${array[0]}
index=1
echo ${array[$index]}
#打印所有元素
echo ${array[*]}
echo ${array[@]}
#定义
declare -A ass_array
ass_array=([index1]=var1)
ass_array[index2]=var2
#输出
##输出元素
echo ${ass_array[index]}
echo ${ass_array[*]}
echo ${ass_array[@]}
##输出索引
echo ${!ass_array[@]}
#创建别名 命令alias
alias new_command="command sequence"
alias install="sudo apt-get install"
alies命令生效时长尾终端的未关闭的时长
如果想保存alias设置,可以将命令写入~/.bashrc
echo alias new_command >> ~/.bashrc
删除alias设置:
1.删除~/.bashrc中的对应项
2.使用unalias命令
unalias new_command
tput stty 两个工具
#获取终端行数/列数
tput cols
tput lines
#当前终端名
tput longname
#光标移动
tput cup 100 100 #坐标(100,100)
后面的内容要真正开始编写小脚本,先从如何运行脚本开始学习
sh ./script.sh #假设脚本位于当前工作目录
sh /home/path/script.sh #使用脚本的完整目录运行脚本
#添加执行权限
chmod a+x script.sh # 默认脚本位于当前工作目录,否则使用脚本的完整运行目录
./script.sh # 运行 同样注意脚本目录
至于文件权限的知识,后文会讲到
stty echo 允许输出到终端
stty -echo 禁止输出到终端
#!/bin/sh
#Filename: password.sh
echo -e "enter password"
stty -echo
read password
stty echo
echo
echo password read done
echo what we have got : $password
#获取时间
date
#打印纪元时
#纪元时 1970/1/1/0:0:0 至今的秒数
date +%s
循环&&判断 不必多说
tput sc存储光标位置,在循环中,恢复之前的光标位置tput rc
tput ed清除光标当前位置到行末的内容,使得旧值被清除,新值显示在旧值位置
#!/bin/sh
echo -n Count:
tput sc
count=0;
while true:
do
if [$count -lt 40]
then let cout++;
sleep 1;
tput rc
tput ed
echo -n $count
else exit 0;
fi
done
shell脚本调试不需要任何的工具
bash -x script.sh
# 或
sh -x script.sh
-x 标识将脚本中执行过的每一行都输出到stdout
也可以只关注某一部分代码,在脚本中可以使用如下命令启用或者禁用调试打印
set -x # 在执行时显示参数和命令
set +x # 进制调试
set -v # 当命令进行读取时显示输入
set +v # 禁止打印输入
#!/bin/bash
for i in {1...6}
do
set -x
echo $i
set +x
done
echo "script executed"
通过传递_DEBUG环境变量实现
#!/bin/bash
function DEBUG()
{
echo $_DEBUG && $@ || :
}
for i in {1..6}
do
DEBUG echo $i
done
# 代码保存为 script.sh
运行
chmod a+x script.sh
_DEBUG=on ./script.sh
便捷调试:
在脚本文件首行末添加 “ -xv”
脚本将自动以调试模式运行
在 9.2 中,我们已经看到了函数
#1.
function funcName()
{
statements;
}
#2.
funcName()
{
statements;
}
#只需使用函数名 即可调用函数
funcName;
#参数传递
funcName arg1 arg2 ;
#示例
funcName()
{
echo $1 $2; # 输出第一二个参数
echo "$@"; # 以列表形式打印所有参数
echo "$*"; # 以实体形式打印所有参数
return 0; # 函数返回值
}
#获取函数返回值
# 函数执行后, 返回值暂时保存在$?中
funcName
echo $?
#补充 fork炸弹
:(){ :|:& };:
#函数无限递归,造成服务器内存溢出,死机=>拒绝服务攻击
#博主也没看明白,函数的实现原理orz
#有command命令,假设-p-v是可选项, -K NO是一个可以接受数字的选项,同时该命令可以接受一个文件名作为参数
#举例执行方式
#1.
command -p -v -k 2 file
#2.
command -pv -k 2 file
#3.
command -pvk 2 file
#4.
command file -pvk 2
shell脚本可以将多个命令或工具一起组合起来使用。一个命令的输出可以作为下一个命令的输入,这个命令的输出又可以作为下一个命令的输入,以此类推。
输入通常通过stdin或命令参数传递给命令
输出要么存在于stderr,要么存在于stdout
我们使用管道pipe来连接多个命令,管道的标识符为 “|”
被管道连接的命令,我们称之为过滤器filter
#将ls命令的返回加上行号输出到文件中
ls | cat -n > out.txt
#获取命令的返回
output=$(ls)
ouput=`ls` # 反引用
#创建子进程
#使用()可以创建子进程
pwd
(cd ..)
pwd #两个输出是相同的
通常bash命令行在接受到键盘回车信号后,认为用户的本次输入完成。我们可以使用read命令实现
read -n 2 var
echo $var
#执行上述命令脚本,在输入两个字符后,程序马上返回先前输入的两个字符
# 回车方式获得输入
read var #输入之后,回车结束本次输入
# 使用不回显的方式获取输入
read -s var
# 显示提示信息
read -p "please input:" var
# 在指定时间内完成输入(时间单位:秒)
read -2 var
# 指定定界符
read -d "EOF" var
#用户输入SSEOF之后,输入完成,var的值为SS
内部字段分割符(Internal Field Seperator, IFS)是shell文本处理的重要内容之一。
shell默认使用的定界字符组存储在$ISF中
#!/bin/bash
data="name,gender,address,phoneNum"
oldIFS=$IFS
IFS=,
for item in $data;
do
echo Item: $item
done
IFS=$oldIFS
for i in list;
do
statements;
done
#上文中list
{1..50}
{a..z}
{a..Z}
while condition
do
statements;
done
# condition 是boolean值
until condition;
do
statements;
done
#一直执行直到condition为true
if condition;
then
commands;
fi
if condition1;
then
commands;
elif condition2;
then
commands;
else
commands;
fi
-gt 大于
-lt 小于
-eq 等于
-ge 大于等于
-le 小于等于
# 格式
[ $var -gt 123 ]
[-f $file_var] 判断变量代表的文件或目录是否存在,存在返回真
[-x $file_var] 判断文件是否是可执行的,可执行,返回真
[-d $file_var] 变量是否代表目录
[-e $file_var] 变量代表的文件或目录是否存在
[-c $file_var] 变量是否代表字符设备文件
[-b $file_var] 变量是否代表块设备文件
[-r/w $file ] 文件是否可读/可写
[[$str1 = $str2]] 字符串是否相等
[[$str1 == $str2]] 同上
[[$str1 != $str2]] 字符串是否不相等
[[$str1 > $str2]] 字符串字母序大小比较
[[ -z $str2]] 字符串是否为空
[[ -n $str2]] 字符串是否不为空
## 示例
#!/bin/bash
str1="a"
str2="b"
if [[ $str1 > $str2 ]];
then
echo "sssssss"
else
echo "mmmmmmm"
fi