#!/bin/bash # 标明用哪种解析器去处理, 固定格式
# 定义变量: =左右不要有空格
# 一般情况下,定义的变量都是字符串; 如果没有空格, 右侧的值可以不用引号包裹
# my_name="Lynn Zhang"
# age=18
# 取变量的值, 可以是 $var 或 ${var}的形式
# 如果做字符串拼接,一般使用 ${var}的格式, 如: "${var}loveyou"
# echo ${my_name} ${age}
# echo '删除变量age'
# unset age
# echo '$age没有打印了' $age
# 常用的环境变量
# $PATH: 设置命令的搜索路径, 以 : 分割
# $HOME: 当前的登录用户
# $SHELL: 当前shell解析器类型
# $LANG: 当前系统语言环境
# printf '$PATH: %s, \n$HOME: %s, \n$SHELL: %s, \n$LANG: %s', $PATH, $HOME, $SHELL, $LANG
# 字符串截取
# ${变量名:start:length}: 从str左边第start开始,截取length的长度(start值从0开始)
# ${变量名:start}: 从str左边第start开始,截取到最后
# ${变量名:0-start:length}: 从str右边第start个字符开始,向右截取length个字符串(start从1开始)
# ${变量名:0-start}: 从str右边第start个字符开始,截取到最后
# ${变量名#*substr}: 从str左侧开始搜索第一个匹配的子串开始,向右截取
# ${变量名##*substr}: 从str左侧开始搜索最后一个匹配的子串开始,向右截取
# ${变量名%substr*}: 从str右侧开始搜索第一个匹配的子串开始,向左截取
# ${变量名%%substr*}: 从str左侧开始搜索最后一个匹配的子串开始,向左截取
# 以下为字符串截取的示例:
# addr="广东省深圳市宝安区广东省南山区"
# echo '从第3个字符开始,截取3个字符' ${addr:3:3}
# echo '从第3个字符开始截取' ${addr:3}
# echo '从倒数第6个字符开始,往后截取3个字符' ${addr:0-6:3}
# echo '从倒数第6个字符开始,往后截取' ${addr:0-6}
# *在哪,决定从哪开始查找
# #代表截取右边的, 一个#代表查找第一个,##代码查找最后一个
# ##代表查找最后一个,截取右边的
# %代表截取左边的 %代表查找第一个, %%代表查找最后一个
# echo '从左侧第一个"省"开始,往右截取' ${addr#*省}
# echo '从左侧查找最后一个"省",往右截取' ${addr##*省}
# echo '从右侧开始查找第一个省,往左边截取' ${addr%省*}
# echo '从右侧开始查找最后一个省,往左边截取' ${addr%%省*}
# 定义数组: 用()包裹, 元素用空格分割
# nums=(1 22 '333' "4444")
# echo '打印所有的元素 ${array_num[@]} 或 ${array_name[*]}' ${nums[@]}
# echo '获取数组的个数 ${#array_name[*]}' ${#nums[@]}
# echo '获取指定元素的字符个数 ${#array_name[下标]}' ${#nums[0]} ${#nums[2]}
# arr=('55555' 666666)
# 拼接数组
# new_arr=(${nums[@]} ${arr[@]})
# new_arr=(${nums[*]} ${arr[*]})
# echo ${new_arr[@]}
# 内置命令
# 1. 设置别名
# alias hello='echo hello'
# unalias hello
# 2. 打印
# -n 不换行输出
# echo -n 'hello '
# echo 'world'
# -e 转义
# echo -e '你了解我吗?\n你这个三炮'
# -e \c 清除换行
# echo -e '你这是太搞笑了\c'
# 换行
# echo
# 3.读取输入
# -a array 把读取到的数据赋值给数组
# -d delimiter 指定读取结束的位置,而不是一个换行符
# -n num 读取num个字符
# -p prompt 显示prompt的提示信息
# -s 静默模式,不会再屏幕上显示输入的字符
# -t seconds 设置超时时间,单位s.
# 3.1 读取多个值给多个变量
# read -p '请输入姓名 年龄 爱好:' name age hobby
# echo "您输入的是 ${name} ${age} ${hobby}"
# 3.2 读取一个字符
# read -n 1 -p "您确定要升级吗?(请输入y/n): " char
# printf "\n"
# echo "您输入的是: $char"
# 3.3 限制时间输入 -s为静默: 输入的不在屏幕显示
# read -n 1 -t 5 -p '请输入是否要升级: y/n' answer
# printf '\n'
# echo $answer
# 退出进程, 并返回错误码
# exit 44
# declare
# 语法: declare [+/-][aArxif] [变量名称=值]
# +/-: -指定变量的属性; +取消变量所设的属性
# a: 设置为普通索引数组
# A: 设置key-value的关联数组
# r: 设置为只读的变量,也可以用readonly
# x: 设置变量为环境变量, 也用export
# i: 设置为int类型的变量
# f: 设置为一个函数变量
# 关联数组
# declare -A map=([one]='one_v' [two]='two_v')
# echo ${map[@]} ${#map[@]}
# 获取指定可以的值: ${关联数组变量名[key]}
# echo ${map['one']} ${map['two']}
# declare -i m_age=18
# echo ${m_age}
# m_age='ab'
# echo ${m_age}
# m_age:只读变量,接下来赋值会报错
# declare -i -r m_age=18
# m_age='abcd'
# expr表达式
# echo `expr 1 + 1`
# result=`expr 2 \* 2`
# echo $result
# 比较运算符
# 推荐使用 [[]], 既可以实现数字和字符串比较,且不需要转义,也不会发生word splitting
# 比较操作符有: ==或=、 !=、 <、 >、 -z、 -n、 $
# if [[ 1 -eq 1 ]]; then
# echo '成立'
# else
# echo '不成立'
# fi
# 布尔运算符
# 布尔运算符有 !(非运算符,表示取反)、-o(or)、-a(and)
# 注意: 布尔运算符必须放在[]或与test配合使用才有效
# 逻辑运算符
# 逻辑运算符有: !(逻辑非)、&&(逻辑的AND)、||(逻辑的OR)
# 使用 && 或 || 必须放在 [[]] 或 (())中才有效,否则报错
# (())计算,里面的值不用$
# ((a=6+1))
# ((a=6+1,b=a+12))
# echo $a $b
# ((a++))
# echo $((6+4))
# 计算结果赋值
# abc=$((9*8))
# echo $abc
# let 用于赋值, 是最简洁的整数赋值命令
# a=4 b=5 c=6
# let d=a+b
# let e=b+c
# echo $d $e
# $[]:括号里只能用于计算,不能用于赋值; 而且只能放一个表达式
# a=$[1+6]
# echo $a
# 文件测试运算符
# -d: 是否是目录
# -e: 检测文件(或目录)是否存在
# -f: 是否是普通的文件(既不是目录,也不是设备文件)
# -r: 文件是否是可读的
# -s: 检测文件是否为空(不为空返回true)
# -w: 文件是否是可写的
# -x: 文件是否是可执行的
# if test -e ~/Desktop; then
# echo '存在'
# else
# echo '不存在'
# fi
# test整数比较
# -eq: 等于则为真
# -ne: 不等于则为真
# -lt: 小于
# -gt: 大于
# -le: 小于等于
# -ge: 大于等于
# if test -8 -gt -9; then
# echo '成立'
# else
# echo '不成立'
# fi
# test字符串比较
# ==: 等于返回0,表示成功
# !=: 不等于
# \<: 小于
# \>: 大于
# -z: 字符串长度为0, 则为真
# -n: 字符串长度不为0, 则为真
# if test "a" \> "b"; then
# echo '成立'
# else
# echo '不成立'
# fi
# bc计算命令: bc [options] [参数]
# -l: mathlib, 使用标准数学库
# -q: quiet, 不显示欢迎信息
# -v: 获取版本信息
# -
# 管道符号的使用: 获取本机IP地址
# 定义函数
# ip() {
# ifconfig | grep 'broadcast' | awk '{print $2}'
# }
# 调用函数
# ip
# switch语句:
# 匹配模式可以使用简单的正则: 如 *、[a-zA-Z]、8|9、[89]
# 格式如下
# case 值 in
# 匹配模式1)
# 语句...
# ;;
# 匹配模式2)
# 语句...
# ;;
# *)
# 语句...
# ;;
# esac
# 示例:
# read -n 1 -p '请输入星期几(0-7): ' week
# case $week in
# 1)
# printf '\n周一\n'
# ;;
# 2)
# printf '\n周二\n'
# ;;
# 3)
# printf '\n周三\n'
# ;;
# 4)
# printf '\n周四\n'
# ;;
# 5)
# printf '\n周五\n'
# ;;
# 6)
# printf '\n周六\n'
# ;;
# # 0|7) # |表示多重选择
# [07])
# printf '\n周日\n'
# ;;
# [a-zA-Z])
# printf '\n输入的是字母\n'
# ;;
# *)
# printf '\n输入的不合法\n'
# ;;
# esac
# while语句
# 格式如下:
# while 条件; do
# 命令...
# done
# 示例;
# read -n 1 -p '请输入一个数字:' num
# echo
# i=0
# while ((i < num)); do
# # let i++
# ((i++))
# if ((i==7)); then
# continue # break
# fi
# echo -e "打印 ${i}"
# done
# select
# 注意: select是无限循环, 输入空值, 或者无效值, 都不会结束循环;
# 只有当遇到break 或按 ctrl+c才能结束循环
# select hobby in '篮球' '足球' '排球'; do
# if test -z $hobby; then
# echo "您没选择"
# else
# echo "您选择了${hobby}"
# fi
# break
# done
# 不符合条件的循环选择
# offerChoose() {
# echo '请选择您的兴趣:'
# select hobby in '篮球' '足球' '排球'; do
# if test -z $hobby; then
# offerChoose
# break
# else
# echo "您选择了${hobby}"
# break
# fi
# done
# }
# offerChoose
# 系统函数
# 1. basename: 用户获取文件名的函数
# 语法: basename [string/pathname] [sufix]
# basename './abc.txt'
# basename './abc.txt' '.txt'
# basename '/Users/LynnZhang/Desktop/abc.txt'
# 2. dirname: 返回目录
# 语法: dirname 路径
# dirname '/Users/LynnZhang/Desktop/abc.txt'
# dirname "$HOME/Desktop/abc.txt"
# 函数
# 语法:
# [ function ] funcname() {
# 命令...
# [return 返回值]
# }
# # 调用
# funcname 参数1 参数2 ...
# 示例:
# function hello() {
# # echo "参数的个数: $#"
# # echo "参数有: $@"
# temp=""
# for v in "$@"; do
# temp="${temp}_${v}"
# done
# # 如果返回值为数字,可以在调用函数后, 通过$?获取
# # return 100
# # 如果返回值非数字, 则需要通过 $()来获取返回值
# # 需要特别注意的是: 通过 $()来接收到的返回值, 为函数体内的第一个echo的内容
# echo $temp
# }
# res=$(hello '11' '22' '33' '44')
# echo "res=============${res}"
# 默认输入输出文件
# Unix/Linux命令运行时, 都会打开三个文件: 标准输入stdin 0, 标准输出stdout 1, 标准错误stderr 2
# 重定向语法
# 命令 > file: 将标准输出数据重定向file, 覆盖方式
# 命令 >> file: 将标准输出的数据重定向到file, 追加的方式
# 命令 < file: 将输入重定向到从file读取数据
# 命令 < file > file2: 将输入重定向到从file1读取数据, 以覆盖的方式将输出重定向到file2. 如: cat < abc.txt > aaa.txt
# 命令 fd>[空格可选]file: 将指定文件描述符将数据重定向输出到file中, 覆盖式
# 命令 fd>>[空格可选]file: 将指定文件描述符将数据重定向输出到file中, 追加式
# 命令 > file fd1>& fd2: 将fd1和fd2文件描述符合并输出到file (需要特别注意的是: 2要写在前面. 如: echo 'hello world' >> err.txt 2>&1 和 echoxxx 'hello world' >> err.txt 2>&1 )
# fd1 <& fd2: 将fd1和fd2文件描述符合并从文件读取
# < ljalf
# heredoc> i
# heredoc> EOF
# 2
# cut命令
# 语法: cut [options] filename
# -f: 提取范围, 获取第几列
# n-: 提取指定第n列 或 字符 或 字节 后面的数据
# n-m: 提取指定第n列 或 字符 或 字节 到 第m列 或 字符 或 字节 直接的所有数据
# n1,n2...: 提取枚举列的所有数据
# -m: 提取指定第m列 或 字符 或 字节 之前的数据
# -d: 自定义分隔符, 默认为制表符
# -c: 提取范围, 以字节为单位进行分割
# -b: 提取范围, 以字节为单位进行分割, 将忽略字符边界, 除非指定 `-n`
# -n: 与 `-b`选项连用, 不分割多字节字符
#
# 示例:
# ifconfig | grep 'broadcast' | cut -d ' ' -f 2
# echo '我和我的祖国,一刻也不能分割' | cut -nb 4-
#### sort命令
# 常用的options
# -n: number, 依照数值的大小排序
# -r: reverse, 以相反的顺序来排序
# -t: 分割字符, 设置排序时所用的分割字符, 默认是空格
# -k: 指定需要排序的列
# -o: 将排序好的结果存入指定的文件
# -u: 输出去重后的结果
# 示例:
# abc.txt的内容如下:
# 王五 50 77
# 张三 30 44
# 李四 40 55
# 赵六 60 66
# 老七 70 22
# 老吴 50 33
# cat './abc.txt' | sort -nr -k2
# cat './abc.txt' | sort -k2nr
# cat './abc.txt' | sort -k2n -k3n
# awk命令
# -F: 指定输入文件拆分分隔符
# -v: 赋值一个用户定义变量
# 内置变量
# ARGC: 命令行参数个数
# FILENAME: awk浏览的文件名
# FNR: 浏览文件的记录数
# FS: 设置输入域分隔符, 等同于 -F 选项
# NF: 根据分隔符分割后的列数
# NR: 行号
# $n: 整条记录的第n个域
# $NF: 最后一列的信息
# 示例:
# abc.txt内容如下:
# 我爱你 亲爱的祖国
# 再回首 云隔断归途
# 我想你 可爱的 童年
# 再回首 荆棘密布
# 你永远不懂 我的爱 我的痛 我内心深处的love
# awk '{ print NF $NF }' abc.txt
# awk '/爱/{print NR $0}' abc.txt
# ifconfig | awk '/broadcast/ { print $2 }' # 打印当前IP
# awk '/^我/' abc.txt # 打印以'我'开头的行
# echo -e 'abc\ndef' | awk '{print $0}'
# echo -e 'abc\ndef' | awk 'BEGIN{print "开始了"}{print $0}END{print "结束了"}'
# echo -e 'abc\ndef' | awk 'BEGIN{print "开始了"}END{print "结束了"}{print $0}' # BEGIN和END的顺序不影响打印
# echo -e 'abc\ndef' | awk -v aaa=0 'BEGIN{print "开始了"} {aaa++} END{print aaa}' # 设置变量
# echo -e 'I love you abc' | awk '{ print $1"&&"$2"&&"$3"&&"$4 }' # 输出域拼接
# echo 'I love you abc ' | awk -v res="" '{for(i=1;i<=NF;i++){res=res$i}} END{print res}' # 输出域拼接
# calc.txt
# 张三 30
# 李四 60
# 王五 40
# awk '{sum+=$2} END{ print sum}' calc.txt # 求和
# 筛选出长度大于3的单词
# echo 'I may not change [the] past, but I can learn from it.' | awk -F "[ ,.]" '{for(i=1;i3) {print $i}}}'
# 单词及字母去重排序: 先对文本进行切割, 遍历出各个单词及其出现的次数, 按照number进行逆序排序, 再取出出现靠前的两个单词及出现频率
# echo 'I may not change the past, but I can learn from it.' | awk -F "[ ,.]+" '{for(i=1;i hello_${i}.txt
# let i++
# done
# filenames=$(ls)
# for name in $filenames; do
# printf '执行命令前: %s' $name
# mv $name "后${name}"
# done
# sed命令
# sed [选项参数] [模式匹配/sed程序命令] [文件名]
# 模式匹配: sed会读取每一行数据到模式空间中, 之后判断当前行是否符合模式匹配的要求, 符合要求就会执行sed程序命令, 否则不会执行sed程序命令; 如果不谢匹配模式, 那么每一行都会执行sed程序命令
# -e: 直接在指令列模式上进行sed的动作编辑, 它告诉sed将下一个参数解释为一个sed指令, 只有当命令行上给出多个sed指令时才需要加 -e 选项;
# -i: 直接怼内容进行修改, 不加 -i 则只是预览, 不会对文件做实质修改
# -f: 后跟保存了sed指令的文件
# -n: 取消默认输出, sed默认会输出所有的文本内容, 使用 -n 后只显示处理过的行
# -r: 使用正则表达式, 默认情况下, 只识别基本的正则表达式
# sed命令功能描述
# -a: add新增, a的后面可以接字符串, 在下一行出现
# -c: change修改, 更改匹配行的内容
# -d: delete删除, 删除匹配的内容
# -i: insert插入, 向匹配行前插入内容
# -p: print打印, 打印出匹配的内容, 通常与 -n 选项合用
# -s: substitute替换, 替换掉匹配的内容
# -=: 用来打印匹配行的行号
# -n: 读取下一行, 遇到n时会自动跳入下一行
sed -e '4aabc' abc.txt