常用指令
linux命令实在有点多,目前感觉比较好的学习方法是先了解和整理一下命令的分类,了解每个分类下一些常用命令功能,然后根据实际需求去查具体用法。使用-h
是一种方式,不过有些可能过于抽象,可以使用一些专门的网站查询命令用法,比如:www.linuxcool.com等。
通常执行一个
sh
脚本只需要运行如下命令:./test.sh
,这种方式往往会报没有运行权限的错误,这时候可以:1)进行授权chmod a+x ./test.sh
;2)换个方式:sh ./test.sh
。后者还可以通过sh +x ./test.sh
来查看脚本执行过程,方便调试。
文件(夹)
指令 | 描述 | 示例 |
---|---|---|
pwd | 打印当前文件路径 | pwd |
file | 确定类型的文件 | file . |
ls ll | 列出目录下的文件,ll是ls -l 的别名-a :显示指定路径中的所有文件,包括隐藏文件-l :显示文件的详细信息,包括文件类型,权限,所属用户,所属用户组,文件大小,上一次修改时间等-h :文件大小以KBytes为单位显示-S :按照文件大小顺序显示,默认从大到小;若要从小到大,可使用-Sr-r :将文件以相反次序显示(ls默认依英文字母a-z次序)-t :以最后一次修改时间排序-d :将目录象文件一样显示,而不是显示其下的文件,只显示当前文件夹-R :递归列出所有目录的文件 | |
cd | 改变目录 | cd . . #进入上级目录 |
dirname | 获取指定路径的父目录 | dirname $(pwd) #返回的是指定路径父目录的绝对路径 |
mkdir | 创建目录 | mkdir ./test |
rmdir | 删除空目录 | rmdir ./test |
rm | 删除文件(夹) | rm -r ./test |
chmod | 设置访问权限 | chmod a+x test.sh chmod 777 test.sh |
ln | 链接文件目录 | |
cmp | 比较二进制文件 | |
diff | 比较两个文件的差异 | |
mv | 移动文件/目录 | mv src dst |
cp | 复制文件/目录 | cp src dst |
chgrp | 变更目录文件所属组 | |
chown | 变更文件目录的所有者 | |
dd | 复制文件并格式化 | |
touch | 修改文件时间或新建文件 | |
find | 查找文件 | |
locate | 快速查找文件 | |
which | 查找可执行程序文件 | |
whereis | 查找执行程序的相关文件 |
关于文件查找命令哪家强,请看这篇:Linux的五个查找命令
文件内容
指令 | 描述 | 示例 |
---|---|---|
nl | 添加行号 | |
echo | 回显变量,几个常用参数:-n :表示内容不换行,默认会换行-e :表示激活转义字符 | echo $SHELL |
printf | 格式化输出,几个常用参数:%s :字符串占位符%-ns :n个字符的字符串占位符,-表示左对齐,默认右对齐%c :字符占位符%d :整数占位符%f :浮点数占位符,默认小数点后6位%-n.mf :浮点数占位符,- 表示左对齐, n 表示显示长度, m 表示小数的位数 | printf "%s %d\n" "Hello World" 123 |
cat | 打印文件所有内容至控制台 | cat test.txt |
more | 打印文件内容至控制台,如果内容超过阈值则部分显示,通过enter查看更多 | more test.txt |
less | 逐页显示文件内容 | |
head | 显示文件开头内容 | |
tail | 显示文件后面内容,在查看日志时使用比较多 | tail -f /usr/local/nginx/log/error.log |
od | 查看特殊格式的文件内容 | |
grep | 查找文本内容,配合管道符使用的场合较多-E :正则匹配,支持多个-e-ve :正则匹配取反,即不包含-a :将 binary 文件以 text 文件的方式搜寻数据-c :计算找到 ‘搜寻字符串’ 的次数-i :忽略大小写的不同,所以大小写视为相同-n :顺便输出行号-v :反向选择,亦即显示出没有 ‘搜寻字符串’ 内容的那一行--color=auto :可以将找到的关键词部分加上颜色 | |
patch | 修补文件 |
cat配合<<EOF
可以实现多行文本输入到指定文件中:
# 将多行文本添加到文件末尾,如果>>改为>就变成覆盖了
cat >> ./text.txt <<EOF
line1
line2
line3
EOF
echo转义字符:
- \n 换行
- \r 回车
- \t 制表符 tab
- \b 退格
- \v 纵向制表符
vi/vim
操作 | 描述 | 示例 |
---|---|---|
模式切换 | 编辑模式 命令模式 插入模式 | 按o:进入编辑模式 按ESC:进入命令模式 按i:进入插入模式 |
文件保存 | :w保存文件但不退出vi 编辑 :w! 强制保存,不退出vi 编辑 :w file将修改另存到file中,不退出vi 编辑 :wq保存文件并退出vi 编辑 :wq!强制保存文件并退出vi 编辑 :q不保存文件并退出vi 编辑 :q!不保存文件并强制退出vi 编辑 :e!放弃所有修改,从上次保存文件开始在编辑 |
账号相关
指令 | 描述 | 示例 |
---|---|---|
whoami | 查看当前用户 | whoami |
进程管理
指令 | 描述 | 示例 |
---|---|---|
ps | Process Status,打印进程信息 | ps |
kill | 杀进程 | kill -9 <pid> |
任务调度
指令 | 描述 | 示例 |
---|---|---|
jobs | 查看当前正在执行的脚本任务 | jobs |
fb/bg | 切换任务到控制台前台/后台 | bg 1 #1为调用jobs命令时任务看到的任务序号 |
nohup | no hangup,忽略HUP信号,让指令在当前会话结束或者当前用户退出登录后可以继续运行;并且将当前指令的输出内容添加到当前目录或者home目录的"nohup.out"文件中 | nohup ping baidu.com |
& | 让当前指令在后台运行,不会阻塞当前用户交互。并且会在指令执行完成后,立即返回到前台,同时输出后台执行时的PID和指令输出的内容 | cat nohup.out & |
来源:Linux中的nohup和& | Linux指令后台执行
ctrl+z
可以挂起(暂停)当前正在执行的的任务
linux软链接
创建软链接命令: ln -s [dir1] [dir2]
dir1
是真实的文件夹dir2
是dir1的软链接
软链接可以理解为,dir2是dir1的快捷方式,进入了dir2,就会自动进入dir1。
例子:
ln -s /home/datasets/JHMDB /home/MOC_detector/data/JHMDB
真正的JHMDB数据集保存在/home/datasets/JHMDB中,/home/MOC_detector/data/JHMDB 是 /home/datasets/JHMDB的软链接。
软链接不仅对文件夹适用,对文件也同样适用。
常用场景
环境变量
配置文件
- zsh:文件位于
~/.zshrc
; - Mac bash:文件位于
~/.bash_profile
。 - Linux bash:文件位于
~/.bashrc
。
进入编辑
通常需要管理员权限才能修改
通过vim修改
打开配置文件:
sudo vi ~/.bash_profile
设置变量:
# 方式1
export http_proxy=http://127.0.0.1:1087
export https_proxy=$http_proxy
# 方式2
export http_proxy=http://127.0.0.1:1087 https_proxy=http://127.0.0.1:1087
通过echo追加修改
echo 'export PS1="\[\033]2;\h:\u \w\007\033[33;1m\]\u \033[35;1m\t\033[0m \[\033[36;1m\]\w\[\033[0m\]\n\[\e[32;1m\]$ \[\e[0m\]"' >> ~/.bash_profile
使修改生效
修改完执行source才能在当前会话立即生效
# 对于bash
source ~/.bash_profile
hosts
位于/etc/hosts
。
系统信息
系统判断
#!/bin/bash
uNames=`uname -s`
osName=${uNames: 0: 4}
if [ "$osName" == "Darw" ] # Darwin
then
echo "Mac OS X"
elif [ "$osName" == "Linu" ] # Linux
then
echo "GNU/Linux"
elif [ "$osName" == "MING" ] # MINGW, windows, git-bash
then
echo "Windows, git-bash"
else
echo "unknown os"
fi
软件是否安装
思路一:使用pm软件查询指定软件是否安装
示例:使用rpm判断是否安装了flutter
#!/bin/bash
check_result=`rpm -qa | grep "flutter"`
echo "check flutter result: $check_result"
不推荐,各个操作系统pm软件不同,很难做到通用
思路二:直接运行软件,检查输出是否符合预期
#!/bin/bash
check_result=$(flutter --version | grep flutter)
echo "check flutter result: $check_result, code:$?"
if [[ $check_result =~ "flutter" ]];
then
echo "flutter has installed."
else
echo "flutter not installed"
fi
check_result=`git --version | grep git`
echo "check git result: $check_result, code:$?"
if [[ $check_result =~ "Git" ]];
then
echo "git has installed."
else
echo "git not installed"
fi
在我的设备中,没有安装flutter,安装了git,运行效果如下:
line 7: flutter: command not found
check flutter result: �� code:1
flutter not installed
check git result: git version 2.32.1 (Apple Git-133), code:0
git has installed.
多了一行报错的命令,这不是我们预期的效果,改进方法如下:
check_result=$(flutter --version 2>&1)
echo "check flutter result: $check_result, code:$?"
if [[ $check_result =~ "flutter" ]];
then
echo "flutter has installed."
else
echo "flutter not installed"
fi
输出效果:没有报错信息了
check flutter result: �� code:127
git has installed.
补充知识点:
0 – stdin (standard input,标准输入)
1 – stdout (standard output,标准输出)
2 – stderr (standard error,标准错误输出)
希望执行某个命令,又不希望在平面上显示结果,可以将输出重定向到/dev/null,如 :echo ‘hello' > /dev/null
简单轮询逻辑
- 实现一个简单的轮训逻辑:
while ((1)) do
> dumpsys cpuinfo
> sleep 0.01 //默认单位为s,也支持m和h
> done
命令行技巧
- 输入
\
可以换行;
编写脚本
掌握上述基本命令,我们可以通过命令行实现我们想要的各种功能,很多重复性流程工作还可以进一步编成脚本,下面介绍如何编写shell脚本。
先查看下自己系统默认的shell:
echo $SHELL
输出:
/bin/bash
查看系统支持的shell:
cat /etc/shells
输出:
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
第一个脚本
下面看一个最简单的shell脚本(test.sh):
#! /bin/bash
echo "hello world shell"
我们运行这个脚本:
bash test.sh
输出:
hello world shell
分析一下:
- 第一行:
#! /bin/bash
指定这个脚本用什么解释器执行,就是前面我们提到过的系统支持的shell。#!
是一个约定的标记,固定写法。 - 第二行:脚本内容
这部分就是你要实现的工作内容,本示例中仅回显一个字符串
关于授权
如果执行上述命令报错:bash ./test.sh: Permission denied
,则表示用户没有脚本的执行权限,进行授权即可:chmod +x test.sh
脚本参数:
$0
获取当前执行脚本的文件名$n
获取脚本的参数,n=1…9 10以后就要${10}$#
脚本后边的总参数$*
获取当前脚本的所有参数"$1 $2 $3"$@
获取当前脚本的所有参数,加了双引号"$@" “$1” “$2” “$3”$?
获取上一个命令的执行状态的返回值,成功为0 不成功非0$$
获取当前执行shell脚本进程的pid$!
获取上一个在后台工作的pid$_
获取在次之前执行命令或脚本的最后一个参数
符号和运算符
符合 | 含义 | 示例 |
---|---|---|
$ | 变量引用符,用于引用变量 | |
$1 | 命令参数,$0 是脚本本身的名字;$1 表示第一个参数,比如bash test.sh a b c ,那么$1 就是a | |
| 算数比较符 | |
| 算数比较符 | |
(()) | 一种数学计算命令,它除了可以进行最基本的加减乘除运算, 还可以进行大于、小于、等于等关系运算,以及与、或、非逻辑运算 | if (( $a == $b )) |
| 或</li><li> !` 非 |
变量
申明变量
定义变量无需特定关键词,直接赋值即可:
# 示例:变量的基本使用
# 定义变量
name=hello
# 使用变量
echo $name
echo ${name}
bj=world
${#bj} #按照字符返回长度
${bj:offset} #从offset位置开始切割到结尾
${bj:offset:length} #从offset位置开始切割指定的长度
删除变量
unset name
只读变量
# 定义只读变量,只读变量不可删除
readonly age=10
# 尝试修改只读变量将会报错:age: readonly variable
# age=11
键盘输入
示例:从键盘接收输入,并赋值给变量
#!/bin/bash
# 带提示语
read -p "Please input a number:" a
# 不带提示语
read b
if (( $a == $b ))
then
echo "a和b相等"
fi
数字运算
(1) let var=算术运算表达式
(2) ((var=算术运算表达式)) 和上面等价,最高效
(3) var=$[算术运算表达式]
(4) var=$((算术运算表达式))
(5) var=$( expr arg1 arg2 arg3 ... ) # 注意两边的空格
(6) declare -i var = 数值
(7) echo '算术表达式' | bc
数学计算要用$((…))
或者$[...]
括起来,记得前面要加上符号$。
a=1
b=2
# 实测这种方式也可以:sum=$[$a+$b]或者sum=$[a+b]
sum=$((a+b))
echo "$a+$b=$sum"
也可以使用expr
表达式:
a=1
# 注意+号两边必须要有空格,否则会被成普通字符串
a=`expr $a + 2`
# 打印a的值,此时变为3
echo $a
$((…))
和$[...]
的区别是:
前者内部数字运算可以使用>、<、=这样的符号,而后者要使用-lt(小于)、-gt(大于)、-le(小于或等于)、-ge(大于或等于)、-eq(等于)、-ne(不等于)。- 内置RANDOM生成器取值范围:0-32767,示例: [ [ [RANDOM%50]
数组
- 声明
# 枚举式
abi_list=(armeabi-v7a arm64-v8a x86 x86_64)
# 定义一个空数组
array=()
array1[0]=a
array1[1]=b
array1[2]=c
# 字符串强转
string="12:34:56"
array=(${string/:/ })
# 使用key替代index来访问数组
declare -A user_info
user_info[name]=devops
user_info[age]=18
# 或者
user_info=([name]=devops [age]=18)
- 访问元素
echo ${array[0]} #获取第一个元素的值
echo ${array[-1]} #获取最后一个元素的值
echo ${array[*]} #所有元素作为一行输出
echo ${array[@]} #所有元素作为多行输出
echo ${#array[*]} #数组的长度
- 遍历元素
# 不推荐
for((i=0; i<4; i++));do echo ${arr[i]}; done
# 推荐
for((i=0; i<${#arr[*]}; i++));do echo ${arr[i]}; done
# 推荐
for i in ${!arr[@]}; do echo ${arr[i]}; done
# 推荐
for item in "${arr[@]}"; do echo $item; done
- 删除元素及数组
unset array2[2] #删除索引数组的第三个元素
unset user_info[age] #删除关联数组中索引为age的元素
unset array2 #删除数组
命令结果
# 获取当前目录赋值给变量,注意变量名可以是关键词,不过不推荐
pwd=`pwd`
# 获取当前目录的父目录并赋值给变量
my_dir=`dirname $(pwd)`
# 获取当前脚本路径,比如:./test.sh,注意这里并不是返回绝对路径
script_dir=$0
流程控制
if
语句
if语法格式:
if condition;then # 必须
...
elif condition;then # 可选
...
else # 可选
...
fi # 必须
condition
通常condition有三种写法:
[ ... ];
或[[ ]]
:通用,前者兼容性好,后者功能多(支持正则);(( ... ))
:仅数值逻辑表达式;test ...;
:通用;
可以用condition快速测试脚本逻辑:[[ " c a s e 1 " = ∗ e n c o d e r c a p a b i l i t i e s [ ] ? ∗ case1" =~ ^*\ encoder\ capabilities[\ ]?* case1"= ∗ encoder capabilities[ ]?∗ ]];echo $?
也支持取反:[! ...]
。下面以[ ... ]
为例介绍不同变量类型的条件表达式写法:
- 数值相关
条件 | 写法 |
---|---|
数字小于60 | if[ $var -lt 60]; if ((a<60)); if [[ a > 60]]; |
- 字符串相关
条件 | 写法 |
---|---|
长度非0 | if[ -n $var]; ` |
长度为0 | if[ -z $var]; ` |
相同 | if[ $a = $b]; |
不相同 | if[ $a != $b]; ` |
模式匹配相同 | if [[ $a == $b ]]; ` |
正则匹配相同 | if [[ $a =~ $b ]]; ` |
- 文件相关
条件 | 写法 |
---|---|
文件或目录是否存在 | if[ -e filename]; 或if[ ! -e filename |
目录是否存在 | if[ -d filename]; |
文件是否存在 | if[ -f filename]; |
是否有读权限 | if[ -r filename]; |
是否有写权限 | if[ -w filename]; |
是否有执行权限 | if[ -x filename]; |
是否是一个字符链接,通常与-d/-f配合使用 | if[ -d filename]; 字符链接示例:ls -l /bin/sh rwxrwxrwx 1 root root 4 Mar 16 2009 /bin/sh -> bash |
- 逻辑运算
条件 | 写法 |
---|---|
与 | [ a = a -a b = b] && echo Y || echo N [[ a==a && b==b ]] && echo Y || echo N |
或 | [ a = a -o b = b] && echo Y || echo N [[ a==a || b==b ]] && echo Y || echo N |
示例
示例1:数字比较
if [ $1 -gt 2 ];
then
echo "greater then 2"
else
echo "less or equals 2"
exit
fi
示例2:字符串判断
# 逐行读取users.list文件
for name in $(more users.list)
do
if [ -n "$name"]; then
echo "name is '$name'"
else
echo "name is null"
fi
done
示例3:字符串模式/正则匹配
[[ 7.6 =~ 7.6.* ]]
echo $?
#输出0
[[ 7.6 == 7.6.* ]]
echo $?
#输出1
[[ apple == a* ]]
echo $?
#输出0
[[ 7.6 =~ 7.6 ]]
echo $?
#输出0
[[ 7.6 == 7.6 ]]
echo $?
#输出0
重要知识点:
$?
表示获取上一行命令的输出;- 使用
[[ a =~ b]]
可以表达a.contains(b)的关系,非常实用;
case语句
语法格式:
case value in
pattern1)
...
;;
pattern2)
...
;;
*)
...
;;
esac
示例
示例1:字符串判断
case $1 in
start)
echo "let's start"
;;
stop)
echo "let's stop"
;;
esac
示例2:数字判断
read -p "Input a number: " n
a=$[n%2]
case $a in
1)
echo "odd number."
;;
0)
ehco "even number."
;;
*)
echo "not number."
;;
esac
for语句
- 语法格式1:穷举式
for i in item1 item2 ... itemN
do
command
done
这种是比较常见的,我们已知所有值进行逐个遍历
- 语法格式2:范围式
for ((i=1;i<=len;i++))
do
command
done
- 语法格式3:迭代式
for var in sequence
do
command
done
示例
示例:打印给定范围的数字
# 打印从1到5的数字
for i in `seq 1 5`; do
echo "$i"
done
# 打印从1到任意输入数字之间的数字
len=$1
for ((i=1;i<=len;i++))
do
echo $i
done
示例:遍历数组的方法
# 定义一个数组,要用空格不要用逗号!!!,用逗号会被当成一个元素
arr=(1 2 3 4)
# 方式一:索引方式遍历
len=${#aar[@]}
for ((i=0;i<len;i++))
do
printf "%s\t%d\n" "$i" ${arr[i]}
done
# 方式二:迭代方式遍历
for item in ${aar[@]}
do
echo $item
done
# 方式三:索引序列迭代方式遍历
for i in "${!arr[@]}"
do
printf "%s-%s\n" "$i" "${arr[$i]}"
done
在上述示例中,
@
都可以被*
替换
示例:索引和迭代的结合
pos=0
array=( 20200630 20210731 20200831 )
for element in ${array[@]}
do
end_date=$element
start_date="${element: 0: 6}01"
let pos++
echo "序号: echo ${pos}, start_date: ${start_date}, end_date: ${end_date}"
done
示例:遍历单层目录,判断文件是否是sh脚本
#!/bin/bash
TESTCHARS=2
head="#!"
PATHNAME=$(pwd)
if [ "$#" -eq 1 -a -d "$1" ]
then
PATHNAME=$1
fi
for file in $(ls $PATHNAME)
do
if test -f $file ; then
# 获取文件头2个字符
headchar=`head -c$TESTCHARS $file`
# 判断是否是“#!”
if test $headchar="$head"
then
echo "file $file is a script"
else
echo "file $file is not a script"
fi
else
echo "file $file is not a script"
fi
done
exit 0
while语句
语法格式:
while condition
do
...
done
示例
- 示例:数字
i=6
while [$i -ge 1] do
echo $i
i=$[$a-1]
done
- 示例:遍历数组
i=0
while [ $i -lt ${#array[@]} ]
do
echo ${array[$i]}
let i++
done
- 示例:打印九九乘法表
i=1
j=1
while (($i <= 9))
do
while (($j<=$i))
do
let "k=i*j"
echo -n "$i*$j=$k "
let j++
done
let i++
let j=1
echo "" #换行
done
函数
自定义函数
#!/bin/bash
# 获取字符串长度
function strLen() {
local str=$1
local ret=0
if [ -n "$str" ]; then
ret=${#str}
fi
# 使用echo把结果返回
echo "$ret"
}
# 函数一定要在调用之前定义,否则报错:command not found
result=$(strLen "haha")
echo "result=$result"
# 数组元素乘以3
function array() {
local arr=($@)
for ((i=0;i<$#;i++))
do
out[i]=$((${arr[i]}*3))
done
echo "${out[@]}"
}
nums=(1 2 3)
result=$(array ${nums[*]})
echo "result=$result"
字符串
正则表达式
参考资料:shell正则
cut
将文件按行进行剪切字节、字符和列并将结果输出。
命令格式:cut [options] filename
选项:
-f
:指定按列号裁剪,从1开始,需要通过-d
来分割和定义列-c
:指定按字符裁剪-b
:指定按字节裁剪- 单列:
-f n
- 多列:
-f n,m
- 开始到n:
-f -n
- n到结束:
-f n-
- m到n:
-f m-n
- 取反:
-f n --complement
,除n列之外的其他列
- 单列:
-d
:指定分隔符,默认是制表符(\t),仅支持单个字符
简单示例:
# 以空格为分隔符,输出每行的第1列
cut -d " " -f 1 test.txt
# 以空格为分隔符,输出每行的第2、3列
cut -d " " -f 2,3 test.txt
应用示例1:选取系统PATH变量值,第2个“:”开始后的所有路径
[bd@localServer ~]$ echo $PATH
/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/bd/bin
#### 其中的2-表示取2以及之后所有的
[bd@localServer ~]$ echo $PATH | cut -d : -f 2-
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/bd/bin
应用示例2:切割ifconfig打印的IP地址
[bd@localServer ~]$ ifconfig eth0 | grep "inet addr" | cut -d : -f 2 | cut -d " " -f 1
192.168.1.102
awk
命令格式:awk [options] ‘pattern{action}’ filename
awk的执行过程是扫描文件的每一行,如果有和模式匹配(pattern)的,就执行后面的一系列动作(acttion)。动作的花括号‘{}’并不是一定要写的,用于和pattern进行分组。
默认情况下,回车换行默认是一行的结束,$表示第几列,举个例子:
awk '{print $3}'
就是输出第三列,$0表示整行输出。
选项:
-F
:指定字段分隔符,默认是空格-v
:初始化绑定变量-f
:从文件读取awk命令,这种适合命令较长的情况
模式:
- 正则:
- BEGIN : 处理开始前执行的操作,可以用来初始化变量等,只会执行一次
- END: 处理完成后执行的操作,只会执行一次
动作:
变量:
除此之外,还有内置变量ARGV数组,ARGV[0]为awk,ARGV[N]下标从1开始是输入的参数
简单示例:
# 输出第一行
awk ‘NR == 1{print;}’ demo.text
# 输出最后一行
awk ‘END{print;}’ demo.text
# 输出第二列
awk ‘{print $2}’ demo.txt
# 输出第一列和第三列
awk ‘{print $1,$3}’ demo.txt
# 输出第二列中包含字符“zhang”的行
awk ‘$2~/^zhang/{print;}’ demo.text
# 输出第二列不包含“yong”的行
awk ‘$2!~/^yong/{print;}’ demo.text
# 输出第二列不包含字符“yong”并且第三列大于70的列
awk ‘$2!~/^yong/ && $3>70{print;}’ demo.text
# 输出第二列不包含字符“yong”并且第三列大于70的列,并且处理开始前和处理完成后输出信息
awk ‘BEGIN{print “start”}$2!~/^yong/ && $3>70{print;}END{print “end”}’ demo.text
# 指定分隔符为 :,并且分别打印第一列,第二列和第三列
awk -F “:” ‘{print $1,$2,$3}’ demo1.txt
进阶用法:
# 支持一维数组、二维数组的创建
awk 'BEGIN {
sites["runoob"]="www.runoob.com";
sites["google"]="www.google.com"
delete sites["google"];
print fruits["google"]
}'
# 使用外部变量
awk -v n=1 -v m=2 'BEGIN{print n, m}'
更多awk使用示例
sed
参考文章:https://blog.csdn.net/l675655077/article/details/88808133
sed [选项] [动作] [inputfile]
-
选项与参数:
-n :使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到终端上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来。
-e :直接在命令列模式上进行 sed 的动作编辑;
-f :直接将 sed 的动作写在一个文件内, -f filename 则可以运行 filename 内的 sed 动作;
-r :sed 的动作支持的是延伸型正规表示法的语法。(默认是基础正规表示法语法)
-i :直接修改读取的文件内容,而不是输出到终端。 -
function:
a :后插行, a 的后面可以是字串,而这些字串会在新的一行出现(目前的下一行)
c :取代行, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行
d :删除行,因为是删除,所以 d 后面通常不接任何参数,直接删除地址表示的行;
i :前插行, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
p :列印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行
s :替换,可以直接进行替换的工作,通常这个 s 的动作可以搭配正规表示法,例如 1,20s/old/new/g 一般是替换符合条件的字符串而不是整行
一般function的前面会有一个地址的限制,例如 [地址]function,表示我们的动作要操作的行。
提示:获取行号可以用grep -n xxx
示例:
# 行号筛选
sed '1d' test.xx # 删除第1行
sed '$d' test.xx # 删除最后一行
sed '1,2d' test.xx # 删除第1、2两行
sed '3,$d' test.xx # 删除第3行及之后的所有行
# 正则筛选/regex/
sed '/2/d' test.txt # 删除所有包含2的行
sed '/^2/d' test.txt # 删除所有2开头的行
# 插入行
sed '1a hello world' test.txt # 在第1行后插入一行,内容为"hello world"
sed '1a \ hello world' test.txt # 在第1行后插入一行,内容为" hello world"
sed '1i hello world' test.txt # 在第1行前插入一行,内容为"hello world"
# 整行替换
sed '1c hello world' test.txt # 替换第1行内容为"hello world"
# 行内部分替换
sed 's/aa/AA/' test.txt # 替换行内第一个aa为AA
sed 's/aa/AA/g' test.txt # 替换行内所有aa为AA
sed '1s/aa/AA/g' test.txt # 替换第1行行内所有aa为AA
sed '5,$s/aa/AA/g' test.txt # 替换第5行及之后所有行的行内所有aa为AA
sed '/^[0-9]/s/aa/AA/g' test.txt # 替换所有数字开头行的行内所有aa为AA
# 函数分隔符自定义
echo 'aabbccaadd' | sed s#aa#AA#g # 其中#作用相当于/
# 仅筛选无动作
sed -n '2p' test.txt #p表示仅输出满足筛选条件的行,加-n是防止全文输出(默认会全文输出)
# 将修改保存到源文件中
sed -i '2d' test.txt # 命令运行之后发现test.txt的第2行没有了
- sed正则支持
expr
整数计算:
注意:数字的左右必须要有空格
expr 2 + 2
expr 2 \* 2
expr 2 / 2
i=5
i=`expr $i + 4`
echo $i
字符串提取:
#!/bin/bash
if expr "$1" : ".*\.pub"* &>/dev/null
then
echo " you are using $1"
else
echo "you .gile"
fi
计算字符的长度(Mac不支持):
expr length "$char"
日期和时间
相关命令
# 2022年 6月20日 星期一 00时05分17秒 CST
date
sleep 3s
统计脚本耗时
用 date 相减:
#!/bin/bash
startTime=`date +%Y%m%d-%H:%M:%S`
startTime_s=`date +%s`
#-------------------------------
echo "code body"
#-------------------------------
endTime=`date +%Y%m%d-%H:%M:%S`
endTime_s=`date +%s`
sumTime=$[ $endTime_s - $startTime_s ]
echo "$startTime ---> $endTime" "Total:$sumTime seconds"
用 time 工具
time sh xxx.sh
# 会返回3个时间数据
# real 该命令的总耗时, 包括user和sys及io等待, 时间片切换等待等等
# user 该命令在用户模式下的CPU耗时,也就是内核外的CPU耗时,不含IO等待这些时间
# sys 该命令在内核中的CPU耗时,不含IO,时间片切换耗时.
时间和时间戳转换
- 时间戳转时间 timestamp2date.sh
#!/bin/sh
function usage(){
echo "-h --help \n" \
" 将10/13位时间戳转换为本地时间 \n"\
" 参数:时间戳,支持10/13位两种 \n"\
" 默认值:当前时间向后5min \n"\
" e.g. 1483430400(10位秒时间戳),1483430400000(13位毫秒时间戳) \n"
exit 1
}
###
os_platform=`uname -s`
if [[ $# -le 0 ]]; then
echo "默认按照当前时间向后5min取值"
if [[ "${os_platform}" = "Darwin" ]];then
echo `date -v+5M +"%Y-%m-%d %H:%M:%S"`
elif [[ "${os_platform}" = "Linux" ]];then
echo `date -d +5min +"%Y-%m-%d %H:%M:%S"`
fi
else
case $1 in
-h|--help)
usage
;;
*)
timestampStr=${1}
length=`echo ${#timestampStr}`
if [[ ${length} -ne 10 ]] && [[ ${length} -ne 13 ]];then
echo "请输入10/13位数字时间戳"
exit 1
elif [[ ${length} -eq 13 ]];then
timestampStr=${timestampStr:0:10}
fi
echo "时间戳位:${timestampStr}"
if [[ "${os_platform}" = "Darwin" ]];then
dateStr=`date -r${timestampStr} +"%Y-%m-%d %H:%M:%S"`
elif [[ "${os_platform}" = "Linux" ]];then
dateStr=`date -d @${timestampStr} +"%Y-%m-%d %H:%M:%S"`
fi
echo "${1}对应的本地时间为${dateStr}"
;;
esac
fi
命令行执行
sh timestamp2date.sh 1507704300000
时间戳位:1507704300
1507704300000对应的本地时间为2017-10-11 14:45:00
- 时间转时间戳 date2timestamp.sh
#!/bin/sh
function usage(){
echo "-h --help \n" \
" 将本地时间转换为13位时间戳(毫秒时间戳) \n"\
" 只有1个参数:本地时间,参数格式:'%Y-%m-%d %H:%M:%S' \n"\
" 默认值:当前时间向后5min \n"\
" e.g. 2017-01-01 16:00:00 \n"
exit 1
}
##时间采用正则匹配
time_pattern="^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}"
os_platform=`uname -s`
if [[ $# -le 0 ]]; then
echo "默认按照当前时间向后5min取值"
if [[ "${os_platform}" = "Darwin" ]];then
echo `date -v+5M +%s`000
elif [[ "${os_platform}" = "Linux" ]];then
echo `date -d +5min +%s`000
fi
else
case $1 in
-h|--help)
usage
;;
*)
dateStr=${1}
echo ${dateStr}
if [[ "${dateStr}" =~ ${time_pattern} ]];then
if [[ "${os_platform}" = "Darwin" ]];then
echo `date -j -f "%Y-%m-%d %H:%M:%S" "${dateStr}" +%s`000
elif [[ "${os_platform}" = "Linux" ]];then
echo `date -d "${dateStr}" +%s`000
fi
else
echo "时间格式不正确,请按照'%Y-%m-%d %H:%M:%S'格式输入,如'2017-01-01 16:00:00' "
fi
;;
esac
fi
命令行执行
sh date2timestamp.sh '2017-10-13 14:38:30'
2017-10-13 14:38:30
1507876710000
其他
数字序列
seq 1 5
:生成1到5的数字序列
脚本调用
脚本入参
shell脚本与batch脚本一样支持调用传参,与bat等其他脚本语言类似,shell预定义了一些参数索引:
$0
:脚本本身$1
:第一个参数$2
:第二个参数,以此类推$?
:上个命令的退出状态(正常退出为0),或函数的返回值$$#
:传参个数
下面以一个简单的脚本为例,演示脚本的调用。
有如下脚本adduser.sh
,用于添加系统用户:
#! /bin/bash
# Usage: ./adduser.sh username [password]
# 参数校验:如果参数数量等于0则终止脚本,返回错误码1
[ $# -eq 0 ] && echo "At least one parameter is required!" && exit 1
# 参数校验:如果用户已存在则终止脚本,返回错误码2
id $1 >& /dev/null && echo "User '$1' already exist!" && exit 2
# 创建用户,如果没有传密码则默认使用用户名作为密码
useradd $1 && if test $# -eq 1; then echo $1; else echo $2; fi | passwd --stdin $1 &> /dev/null && echo "Add user $1 success" && exit 0
# 在useradd 或者 passwd时出现了异常,很有可能是权限不足所导致
echo "Something above goes wrong." && exit 3
脚本非常干练,这里进行一下解释:
$#
表示参数数量;[ arg... ]
是条件表达式,所以[ $# -eq 0 ]
是判断是否传参(数量等于0表示未传参);id
指令查询需要创建的用户是否存在,如果用户存在,表达式id $1
的返回值($?)
为0;>& /dev/null
可以隐藏表达式id $1
的输出信息(重定向到空设备),batch中也有相应的操作:pause >null
;if test $# -eq 1; then echo $1; else echo $2; fi
判断用户是否设置了第二个参数,如果没有参数二,使用用户名作为密码,这里使用了管道“|”将表达式结果流转给passwd
指令;useradd username passwd password
添加系统用户的命令,成功则返回0;
脚本选项
现有以下脚本test.sh
:
#!/bin/sh
for option
do
echo $option
done
然后我们调用该脚本:./test.sh
,输出:
-a
a
-b
b
看一个更完整的示例:
for option
do
case $option in
-help | --help | -h)
want_help=yes
;;
-exec-prefix=* | --exec-prefix=*)
EPREFIX=`expr "x$option" : "x-*exec-prefix=\(.*\)"`
;;
-*)
{ echo "error: unrecognized option: $option Try \`$0 --help' for more information." >&2
{ (exit 1); exit 1; };
}
;;
esac
done