常用命令,归档参考
xargs
# 可以将输出转换为其他命令的输入参数(非命令的输入)
# -d 界定符,同 cut -d
# -n 每行 Item 数量
# -I 指定一个替换字符,常用"{}"
# -t 打印出最终要执行的命令,然后直接执行,不需要用户确认
# -P 指定 xargs 后的子进程并发数,若为 0 则不限制,将自动根据参数数量 fork 相应个子进程
# 尽可能的并发多个 wget 进程进行文件下载:
cat ips.txt | xargs -n 1 -P 0 -I {} wget -q -e http_proxy={} -O {} "http://domain/path/to/url"
# 比如并发下载
urls=(
"http://example1.com"
"http://example2.com"
"http://example3.com"
)
num=${#urls[@]}
printf "%s\n" "${urls[@]}" | xargs -n 1 -P $num curl -O
wait
# wait 阻塞当前进程的执行,直至指定的子进程执行结束后才继续执行
# 使用 wait 可以在 bash 脚本"多进程"执行模式下起到一些特殊控制的作用
# 若 wait 后不带任何进程号或作业号,则阻塞当前进程的执行,直至当前进程的所有子进程都执行结束后才继续执行
# 格式
# wait [进程号或作业号]
# 如 wait 23 or wait %1
# ——————————————————————————————————————————————————————————————————————————————————————————
#!/bin/sh
echo "1"
sleep 5&
echo "3"
echo "4"
wait
# 会等待 wait 所在 SHELL 的所有子进程执行结束,本例中是 sleep 5 这句
echo "5"
uuidgen
# 生成 UUID 值
# -r, --random generate random-based uuid
# -t, --time generate time-based uuid
# -V, --version output version information and exit
# -h, --help display this help and exit
uuidgen -t
# 19df1690-96aa-11eb-93e1-286ed489f459
tree
# 通过树的形式列出当前目录-L 代表深度如果为1则只列出一层目录
tree -L 1 .
trap
# trap 是内建命令,用于在脚本中指定信号如何处理
trap -p # 将当前的 trap 设置打印出来
trap -l # 打印所有信号
trap "cmd" signals # 当接收到指定信号时执行指定命令
trap signals # 若没有明亮部分则默认将信号处理复原,如: trap INT 即恢复 Ctrl+C 退出
trap "" signals # 忽略信号,可多个,如: trap "" INT 表明忽略 SIGINT 信号 => 按 Ctrl+C 也不能使脚本退出
trap "cmd" EXIT # 脚本退出时执行 cmd
trap "cmd" ERR # 当命令出错,退出码非0,执行cmd
trap "cmd" RETURN # 当从 SHELL 函数返回、或用 SOURCE 执行另一脚本文件时执行 commands
trap -- signals # 删除捕获
split
split:
-a # 指定后缀长度
-d # 用数字作后缀
-b # 根据容量分割,单位是 byte,如 split -b 10k -d -a 3 dateFile
-l n # 根据行数分割,合并时 cat file* >> file
# 数字方式命名,每份 30M(若按行分隔则使用 -l),排序后缀占 3 位
split -d -b 30m -a 3 abc.tar.gz
# 合并文件
cat x00* > abc.tar.gz
rename
# 提供用字符串替换的方式批量的更改文件名
# -v 显示修改的文件名
# -n 不执行任何的操作,主要用来测试(查看效果)
# -f 强制修改
# ——————————————————————————————————————————————————————————————————————————————————————————
rename "s/AA/aa/" * # 把文件名中的 AA 替换成 aa
rename "s/\.html/\.php/" * # 修改文件名中的 .html 后缀替换为 .php
rename "s/$/\.txt/" * # 批量添加文件后缀
rename 's/ //g' * # 去除文件名的空格
mktemp
# 生成临时文件
FILE_PATH=$(mktemp)
ll $FILE_PATH
# -rw------- 1 root root 0 Mar 26 15:32 /tmp/tmp.R5Cg3RC8Ka
# 生成临时目录
DIR_PATH=$(mktemp -d)
ll $DIR_PATH
# total 0
# 生成临时目录(内存)
mktemp --tmpdir=/dev/shm 2>> /dev/null
hexdump
# 查看任何文件的十六进制编码,常用于查看二进制文件
-n # Length 只格式化输入文件的前length个字节
-C # 输出规范的十六进制和 ASCII 码(常用)
-c # 单字节字符显示
-b # 单字节八进制显示
-d # 双字节十进制显示
-o # 双字节八进制显示
-x # 双字节十六进制显示
-s # 从偏移量开始输出
-v # 不压缩重复行
hexdump -Cv /tmp/file1.txt
# 00000000 49 20 6e 65 65 64 20 74 6f 20 62 75 79 20 61 70 |I need to buy ap|
# 00000010 70 6c 65 73 2e 0a 49 20 6e 65 65 64 20 74 6f 20 |ples..I need to |
# 00000020 72 75 6e 20 74 68 65 20 6c 61 75 6e 64 72 79 2e |run the laundry.|
# 00000030 0a 49 20 6e 65 65 64 20 74 6f 20 77 61 73 68 20 |.I need to wash |
# 00000040 74 68 65 20 64 6f 67 2e 0a 49 20 6e 65 65 64 20 |the dog..I need |
# 00000050 74 6f 20 67 65 74 20 74 68 65 20 63 61 72 20 64 |to get the car d|
# 00000060 65 74 61 69 6c 65 64 2e 0a |etailed..|
# 00000069
# 第一列表示文件文件偏移量,第二列以两个字节为一组的十六进制
# 注意并非所有十六进制值都有对应的可打印 ASCII 字符,这种情况下将显示点 . 或其他占位符
# ——————————————————————————————————————————————————————————————————————————————————————————
# 双字节十进制显示
echo -n A | hexdump -d
# 0000000 00065
echo -n A | hexdump -C -d
# 00000000 41 |A|
# 0000000 00065
# 0000001
fock
# flock [-sxon] [-w timeout] lockfile [-c]command...
# flock [-sxun] [-w timeout] fd
# Args ...
# -s 为共享锁,在定向为某文件的FD上设置共享锁而未释放锁的时间内,其他进程在该文件FD上设置独占锁的请求失败,试图在定向为此文件的FD上设置共享锁的请求会成功
# -x 为独占或排他锁,在定向为某文件FD设置独占锁而未释放锁的时间内其他进程试图在此文件FD上设置共享锁或独占锁都会失败。只要未设置-s参数,此参数默认被设置
# -u 手动解锁,一般情况不必须,当FD关闭时系统会自动解锁,此参数用于脚本命令一部分需要异步执行,一部分可以同步执行的情况
# -n 为非阻塞模式,当试图设置锁失败,采用非阻塞模式,直接返回1,并继续执行下面语句。
# -w 设置阻塞超时,当超过设置的秒数,就跳出阻塞,返回1,并继续执行下面语句。
# -o 必须是使用第一种格式时才可用,表示当执行command前关闭设置锁的FD,以使command的子进程不保持锁。
# -c 执行其后的 comand
# crontab 借助 flock 防止重复执行
0 23 * * * (flock -xn ./test.lock -c "sh /root/test.sh") # -n 为非阻塞模式
# ——————————————————————————————————————————————————————————————————————————————————————————
#!/bin/bash
{
flock –n 3
[$? –eq 1] && { echo fail ;exit}
echo succeed
# Doyour task here …
} 3 <> mylockfile
# 首先使用<>打开mylockfile 并定向到文件描述符3,而定向文件描述符是先于命令执行的,因此假如要执行的语句段中需要读写mylockfile文件
# 例如想获得上一个脚本实例的pid,并将此次的脚本实例的pid写入mylockfile
# 此时直接用>打开mylockfile会清空上次存入的内容,而用<打开mylockfile当它不存在时会导致一个错误
# 其次以非阻塞的方式打开mylockfile,flock –n 3,其中3是mylockfile的文件描述符,若能够正常获取锁(默认是排它锁),则继续往下执行,否则返回1
# 该返回码能够在接下来的语句中[ $? –eq 1 ] 进行判断,若为1,则输出失败并退出当前脚本
find
-name # 按文件名查找: find -name "*.txt" cp -ap {} {}.bkup \;
-iname # 按文件名查找: find -iname "MyCProgram.c"(不匹配大小写,相当于 grep -rl -i "MyCProgram.c" .)
-maxdepth # 最大目录搜索深度: find / -maxdepth 10 -exec basename {} \; (仅输出指定目录深度下的文件名 )
-mindepth # 最小目录搜索深度: find / -maxdepth 5 -mindepth 2 -name "*.conf" -exec ls -l {} \;
-not # 相反匹配: find -maxdepth 1 -not -iname "被排除的文件名"
-inum # 使用文件系统inode号查找文件: find -inum 804180 -exec rm {} \;
-perm # 按对象权限类型搜索(格式: -perm -u=rwx / -perm 0777 )
-type # 搜索文件类型(f,d,s,c,b,...): find . -type f -iname "*.mp3" -exec rename "s/ /_/g" {} \;
-empty # 内容为空的文件: find / -empty (当搜索路径被指定为绝对路径时其输出也是绝对路径!)
-size # 指定小于或大于特定大小的文件: find / -size +60k -exec ls -hl {} \;
-mmin # 指定小于或大于分钟范围内容被修改过的文件
-mtime # 指定小于或大于天数范围内容被修改过的文件
-amin # 指定小于或大于分钟范围被访问过的: find -mmin -/+60 -exec ls -l {} \;
-atime # 指定小于或大于天数范围被访问过的: find -atime -/+1
-cmin # 指定小于或大于分钟范围被修改过内容的
-ctime # 指定小于或大于天数范围被修改过内容的
-never # 查找比某一文件修改时间还要新的文件: find -newer /etc/passwd
-anewer # 查找比某一文件访问时间还要新的文件
-cnever # 查找比某一文件状态改变时间还要新的文件
-xdev # 仅在当前文件系统中搜索: find / -xdev -name "*.log"
-user # 指定用户的文件: find / -user root
-nouser # 无属主的
-nogroup # 无属组的
-readable # 可读的
-writable # 可写的
-fstype # 属于特定文件类型的
-gid # 特定属 GID 的文件
-regex # 按正则进行搜索: find . -regex ".*/[0-9]*/.c" -print
-prune # 不进入子目录搜索(仅对当前目录)
-exec # 对搜索结果执行的操作: find -name "*.html" -exec ./bash_script.sh '{}' \;
-execdir #
-ok #
-okdir #
-path # 排除 /proc 目录: find / ! -path "/proc" -type f -name '*.jar'
-delete # 对搜索结果执行删除动作,例如 find /tmp -depth -name core -type f -delete
# ——————————————————————————————————————————————————————————————————————————————————————————
# 输出文件大小并按大小排序
find /tmp -type f -print0 | xargs -0 ls -Ssh1 --color
# 查找特定时间范围内的文件
find /log/ -newermt '2013-08-08' ! -newermt '2013-09-01' -type f
find test \(-path test/test4 -o -path test/test3 \) -prune -o -name "*.log" -print
# 查找某目录下超过固定大小的文件,并清空其文件内容
find /data/logs/apache/ -type f -size +1G -exec sh -c "> {}" \;
date
%F # 即: yyyy-mm-dd(+%Y-%m-%d)
%y # 年份的最后两位数字 (00.99)
%Y # 完整年份 (0000-9999)
%m # 月份 (01-12)
%d # 日 (01-31)
%H # 小时(00-23)
%M # 分钟(00-59)
%S # 秒(00-60)
%b # 月份 (Jan-Dec)
%B # 月份 (January-December)
%D # 直接显示日期 (mm/dd/yy)
%T # 直接显示时间 (24小时制)
%h # 同 %b
%n # 下一行
%t # 跳格
%I # 小时(01-12)
%k # 小时(0-23)
%l # 小时(1-12)
%p # 显示本地 AM 或 PM
%r # 直接显示时间 (12小时制,格式为 hh:mm:ss [AP]M)
%s # 从1970年1月1日 00:00:00 UTC 到目前为止的秒数
%X # 相当于 %H:%M:%S
%Z # 显示时区
%a # 星期几 (Sun-Sat)
%A # 星期几 (Sunday-Saturday)
%c # 直接显示日期与时间
%j # 一年中的第几天 (001-366)
%U # 一年中的第几周 (00-53) (以 Sunday 为一周的第一天的情形)
%w # 一周中的第几天 (0-6)
%W # 一年中的第几周 (00-53) (以 Monday 为一周的第一天的情形)
%x # 直接显示日期 (mm/dd/yy)
%N # 纳秒
# —————————————————————————————————————————————————————————————————————————————————————————— Example
date --date='@2147483647'
# Convert seconds since the epoch (1970-01-01 UTC) to a date
date "+%Y-%m-%d %H:%M:%S.%3N"
# 毫秒精度 2024-05-25 14:48:32.886
echo '2024-05-25 14:16:33.323' | date "+%H:%M:%S.%3N" -f -
# 从标准输入读取时间戳文本,并输出指定格式的时间戳
date "+now time: %y-%m-%d %H:%M:%S"
# now time: 17-08-15 22:24:36
date "+三年前的此刻是: %y-%m-%d %H:%M:%S" -d "-3 years"
# 三年前的此刻是: 14-08-15 22:25:52
date "+三个月后时间是: %y-%m-%d %H:%M:%S" -d "+3 months"
# 三个月后时间是: 17-11-15 22:26:38
date "+十天之后时间是: %y-%m-%d %H:%M:%S" -d "+10 days"
# 十天之后时间是: 17-08-25 22:27:22
date -d "+8 hours 2021-08-27 08:08:08" "+%d-%m-%Y %H:%M:%S"
date -d "-8 hours 2021-08-27 08:08:08" "+%d-%m-%Y %H:%M:%S"
# 根据给定的时间加减8小时
ps -p $PID --no-headers -o lstart 2>>/dev/null | xargs -I {} date -d {} "+%d-%m-%Y %H:%M:%S"
# 根据给定的时间格式化输出
# 设置系统时间的几个例子(足够智能)
date -s "20171027 20:49:30"
date -s "20:49:30 20171027"
date -s "20:49:30 2017/10/27"
date -s "20:49:30 2017-10-27"
date -s 2021-10-5
date -s 16:30
# 一年中的第几天
date "+%j"
# 300
# Unix 时间戳转换
date -d '@1615909456'
# Tue Mar 16 23:44:16 CST 2021
# Unix 时间差
date -d '1970-01-01 00:00:01' +%s
# -28799
# 偷懒的方法
date "+%F %T"
# 2017-10-27 20:52:33
# 昨天日期(1天前)
date -d last-day +%Y-%m-%d
date -d "1 days ago" +%Y-%m-%d
date -d '-1 days' +%Y-%m-%d
# 下周一日期
date -d 'next monday' +%Y-%m-%d
# 明天日期
date -d next-day +%Y-%m-%d
date -d '1 days' +%Y-%m-%d
# 上个月的今天
date -d last-month +%Y-%m-%d
# 下个月的今天
date -d next-month +%Y-%m-%d
dirname & dirname
pwd
# /etc/sysconfig/modules
basename `pwd`
# modules
dirname `pwd`
# /etc/sysconfig
grep
# -a 不忽略二进制的数据
# -A 显示匹配行及其向下 N 行,例如 grep -A 3 -F "string..."
# -B 显示匹配行及其向上 N 行
# -C 显示匹配行及其上下 N 行
# -e 使用正则搜索
# -E 使用扩展正则搜索
# -o 只显示被匹配的模式内容,例如 grep -o -e "x\{1,2\}.*"
# -c 统计输出被匹配行的次数
# -n 显示匹配行的行号
# -d 说明要查找的对象是目录
# -r 对目录进行递归式的搜索
# -f 从文件中读取要配匹配的模式,例如统计 file2 中有而 file1 中没有的行: grep -vFf file1 file2
# -F 将范本样式视为固定字串(非正则速度快,相当于 fgrep,例如统计两个文件共有的行: grep -Ff file1 file2
# -h 仅输出匹配内容而不显示被匹配的文件名
# -H 输出匹配内容的同时也输出被匹配文件名
# -l 输出被匹配的文件的文件名,常用于针对路径的递归搜索,例如 grep -rl "关键字" .
# -L 输出未被匹配的文件名,常用于针对路径的递归搜索,例如多文件查询: grep -L "str" logs1.log logs2.log
# -i 忽略关键字大小写的差异
# -q 不输出任何信息,仅用于脚本中判断是否匹配到相关内容`
# -s 不显示错误信息
# -v 排除查找(输出没有被匹配的行)
# -y 此参数的效果和指定 -i 参数相同
# -w、--word-regexp 只显示全字符合的列
# -x、--line-regexp 只显示全列符合的列
# --color 对匹配进行高亮显示
# --exclude 过滤不需要匹配的文件类型,例如 grep -rl "keyword" . --exclude *.log
# --include 指定匹配的文件类型
# 常用参数: -A -B -C -o -E -P -F -w -i -rl -n -v -c -q
# ——————————————————————————————————————————————————————————————————————————————————————————
# 统计 F2 文件和 F1 文件中都存在的
grep -Fv F2 F1
# 统计 F2 文件中有而 F1 文件中没有的
grep -Fv F2 F1
# —————————————————————————————————————————————————————————————————————————————————————————— PERL
# 使用 perl 正则
grep -P '^\d{3}-\d{2}-\d{4}$' file.txt
# 使用 perl 正则,借助零宽断言
echo 'test:123abc123' | grep -oP '(?<=\d{3})\w+(?=\d{3})'
# abc
# 使用 perl 正则,借助 (?P<name> ...) 的语法来定义命名分组,并通过 \g<name> 或 \k<name> 来引用命名分组!
echo 'test:123abc123' | grep -oP '(?P<X>\d{3})\w+(\g<X>)'
# 123abc123
echo 'test:123abc123' | grep -oP '(?P<X>\d{3})[[:alpha:]]+(\g<X>)'
# 123abc123
echo 'test:123abc123' | grep -oP '(?P<X>\d{3})\w+(\g<X>)' | sed -E 's/[[:alpha:]]+//g'
# 123123
# ——————————————————————————————————————————————————————————————————————————————————————————
cat <<'EOF' | /bin/bash
strings="test:123abc123"
if [[ "$strings" =~ (123) ]]; then
echo -n "${BASH_REMATCH[0]}"
echo -n "${BASH_REMATCH[1]}"
echo
fi
EOF
# 输出 123123
printf
printf 'number: %-+8.2f \t string: %s \n ' $number $string
#
# 格式符:
# %d,%i 十进制整数
# %s 字符串
# %f 浮点数,例如 %-8.2f 表示左对齐且宽度为 8,并在其后保留两位小数(符号 + 表示显示数据类型的符号)
# %u 不带正负号的十进制值
# %% 表示 % 自身
#
# 转义:
# \f 换页
# \t 水平制表
# \v 垂直制表
# \b 后退
# \n 换行(输出时默认不会换行)
# \r 回车
# \\ 自身
# 以 0 填充长度为 5
printf "%05d\n" 15
# 00015
printf "[ %05d ]\n" {00..05}
# [ 00000 ]
# [ 00001 ]
# [ 00002 ]
# [ 00003 ]
# [ 00004 ]
# [ 00005 ]
sed
sed [options] 'command' file(s)
sed [options] -f scriptfile file(s)
# Args ...
# -n 不输出模式空间中未被改变的内容
# -i 就地编辑原文件,并且若提供了后缀则进行备份,例如 sed -i.bak 's/1/2/g' file
# -e 在同一行中执行多条编辑命令,例如 sed -e 's/1/2/g' -e 's/a/b/g' 或 sed -r 's/1/2/g;s/a/b/g'
# -r,-E 使用扩展正则
# -f 调用脚本文件
# --debug
# command parameter ...
# i 在当前行上方插入文本,即 Insert
# c 修改当前行整行的文本,即 Change
# a 在当前行下方插入文本,即 Append
# p 输出模式空间中的内容,即 Print,如 -n '1~2p' 输出奇数行(从第1行算起每2行输出1次)
# d 删除当前行(删除模式空间,进行下一个循环)
# e 将替换后的新字符串作为命令执行,如 echo 'cmd hello' | sed 's/cmd/echo/e' 将输出 hello
# r 从指定文件的内容读入到该行,如 r fileName
# w 将模式空间的内容追加到文件,如 w fileName
# W 将模式空间第一行内容追加到文件,如 W fileName
# D 将模式空间第一行内容删除并重新执行脚本顶端的命令
# s 替换指定字符
# l 列表不能打印字符的清单
# h 用模式空间的数据覆盖掉保持空间
# H 将模式空间的数据追加到保持空间,例如 '1,2H;$G' 表示将第 1 至第 2 行全部追加到文件末尾
# g 将保持空间的数据覆盖掉模式空间
# G 将保持空间的数据追加到模式空间,例如 '1{h;d};$G' 表示剪切第一行内容并将其追加到最后一行
# x 替换两个空间中的数据,例如 '/A/h;/B/x' 将关键字 A 与关键字 B 所在行互换
# n 读取下一行并使用后续命令处理新的行而非从头开始,例如 -n 'p;n' 表示打印奇数行
# N 将下一行追加到当前模式空间并在二者间嵌入换行符,且改变当前处理的行号
# P 输出模式空间中第一行的内容
# = 打印当前行号,例如 -n '/root/=' 表示输出 root 关键字所在的行号,相当于 grep -n 'root'
# b lable 分支到脚本中带有标记的地方,若分支不存在则分支到脚本末尾
# t label if 分支,从末行开始,若满足或 T/t 将导致分支到带有标号的命令处,或到脚本的末尾
# T label 错误分支,从末行开始,若发生错误或者 T/t 将导致分支到带有标号的命令处,或到脚本的末尾
# ! 排除/取反,对未被选定的部分执行后面的操作
# # 把注释扩展到下一个换行符以前
# q 退出执行,如 '10q' 表示打印第 10 行后退出
# g 全部替换,例如 's/A/B/g' 表示将所有 A 改为 B、's/A/B/2' 表示将所有 A 改为 B 且仅替换 2 次
# y 将单个字符转为其他字符(不使用正则),例如 'y/123/abc/g' 表示将1替换为a、2替换为b、3替换为...
# & 被匹配模式匹配住的所有内容,例如 's/123/abc&/g' 表示将 123 替换为 abc123
# \1 此处数字即匹配模式中分组的下标,例如 -E 's/(123).*(789)/\2\1/' 表示将 789 与 123 的位置互换
# ——————————————————————————————————————————————————————————————————————————————————————————
# examples
sed '/^$|#/!p' # 不输出空行或注释行
sed '2,$d' # 从第 2 行删到末尾
sed '/ccc/{x;p;x;}' # 在匹配行前加入空行
sed '{N;s/\n/\t/;}' # 将偶数行与其上面的奇数行合为一行,其中 N 将第 2 行追加到模式空间,此时模式空间 2 行,然后替换换行符
sed 10q # 输出前 10 行
sed '{$!N;$!d;}' # 输出后 2 行
sed '$d' # 删除最后一行
sed '{n;d;}' # 删除偶数行
sed '{n;G;}' # 在偶数行后插入空行
sed '{n;n;G;}' # 在第 3、6、9、12、… 行后插入空行
sed G # 在每行后面增加一行空行
sed 'G;G' # 在每行后面增加两行空行
sed '/^$/d' # 删除空白行
sed -n '1,5p' # 输出第 1 至 5 行
sed -n '5,/^test/p' # 输出第 5 行到以 test 开头的行之间的数据
sed -n '/test/,/check/p' # 输出含 test 的行到 check 的行之间的数据
sed -nE '/^.{65}/p' # 输出含 65 个或以上字符的行
sed '$!N;s/\n/ /' # 将 2 行链接生成一行,模拟 paste
sed -n '/regexp/{n;p;}' # 查找 regexp 并仅将匹配行的下一行输出
sed -n '/regexp/{g;1!p;};h' # 查找 regexp 并仅将匹配行的上一行输出
sed -n 's/foo/bar/3' # 将 foo 替换成 bar,只替换第 3 次被匹配的关键字
sed -n 's/foo/bar/3g' # 将 foo 替换成 bar,从第 3 次被匹配的位置开始往后全部替换
sed '/baz/!s/foo/bar/g' # 将 foo 替换成 bar,且只在没有出现 baz 关键字时替换
sed -n '3~7p' # 从第 3 行开始,每 7 行显示一次,或 sed -n '3,${p;n;n;n;n;n;n;}'
gsed '0~8d' # 删除 8 的倍数行
sed -n '$=' # 模拟 wc -l
sed '{1!G;h;$!d;}' # 模拟 tac 命令进行逆序输出
sed '$!N;$!D' # 显示后两行,模拟 tail -2
sed -e :a -e '$q;N;11,$D;ba' # 模拟 tail 显示文件中的最后 10 行
sed '/^$/d;G' # 将原所有空行删除并在每行后增加一空行,这样在输出的文本中每一行后面将有且只有一空行
sed 's|[0-9]|<&>|g' # 把文件中的数字都替换成 <num> 样式(右侧的 g 表示全局替换,sed 默认仅替换第 1 个匹配)
sed 's|[0-9]|<&>|2' # 把前面正则表达式找到的第二列以后内容进行替换
sed 'n;d' # 将第一个脚本所产生的所有空行删除(即删除所有偶数行)和 ed '/^$/d' 的效果一样。
sed = filename # 对文件中的所有行编号(行号在左,文字右端对齐)
echo 1a2b | sed -r 's/.(.)../\1/g' # 输出 a
sed -e :a -e '$d;N;2,10ba' -e 'P;D' # 删除最后 10 行
sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//' # 模拟 rev 命令倒置行字串输出
sed '/./=' filename | sed '/./N; s/\n/ /' # 对文件中的所有行编号,但只显示非空白行的行号。
sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//' # 将行中的字符逆序排列,第一个字成为最后一字,……(模拟"rev")
sed '$!N;s/\n/ /' # 将每两行连接成一行,类似 "paste"
sed -e :a -e '/\\$/N; s/\\\n//; ta' # 如果当前行以反斜杠 \ 结束,则将下一行并到当前行末尾并去掉原来行尾的反斜杠
sed '$!N;$!D' # 模拟 tail -2 命令显示文件中的最后 2 行
sed -e '/./{H;$!d;}' -e 'x;/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d # 显示含 "AAA"、"BBB"、"CCC" 3 者任 1 字串的段落
sed '$!N; s/^\(.*\)\n\1$/\1/; t; D' # 删除除重复行外的所有行,模拟 uniq -d
sed 's/\(.*\)foo/\1bar/' # 替换最后一个 foo
sed 's/\(.*\)foo\(.*foo\)/\1bar\2/' # 替换倒数第二个 foo
awk
# awk 用于处理文本和数据,执行逐行扫描,寻找匹配模式的行并执行自定义操作,支持自定义函数和动态正则表达式等先进功能 ...
# 若未指定模式,则所有的行都被处理
# 若未指定动作,则把输出到标准输出
awk -F 'pattern' 'condition{action}' filename
# 若不指定 fileName 或指定 - 则处理标准输入
# 特殊模式(若存在多个则以定义时的顺序处理)
# BEGIN{} 处理前先执行(可不加文件参数)
# END{} 处理完再执行
# —————————————————————————————————————————————————————————————————————————————————————————— 内置变量
# ARGC 命令行参数数量
# ARGV 命令行参数组成的数组
# $0 完整一行记录
# $n 当前记录的第 n 个字段,字段分隔符由 FS 变量定义
# ARGIND 命令行中当前文件的位置,从 0 开始
# CONVFMT 数字转换格式,默认 %.6g
# ENVIRON 环境变量数组,字典类型的关联数组
# ERRNO 最后一个系统错误的描述
# FIELDWIDTHS 定义字段宽度的列表,默认为空格分隔 => FIELDWIDTHS="4 2 2 2 2 2" 表示$1宽度是4、$2是2、$3是2 ....
# FILENAME 当前文件名
# IGNORECASE 非 0 值则为真,匹配时是否忽略大小写
# FS 字段分隔符,默认是任何空格
# RS 一条记录的分隔符,默认 \n
# NF 当前记录的字段数,列数
# NR 当前行号,亦代表当前针对所有文件已处理的累计总行数
# FNR 与 NR 类似,但它是针对当前非第一个文件中已处理的行数,所以仅当处理第一个文件时满足 NR==FNR
# OFMT 数字的输出格式,默认 %.6g
# OFS 输出字段分隔符,默认是空格
# ORS 输出记录分隔符,默认是 \n
# RLENGTH 由 match 函数所匹配的字符串长度
# RSTART 由 match 函数所匹配的字符串的第一个位置
# SUBSEP 数组中下标的分隔符(默认 /034)
# ...
# —————————————————————————————————————————————————————————————————————————————————————————— 内建函数
# sub(r,s) 相当于 sed 's/r/s/'
# substr(s,p) 返回字符串 s 中从 p 开始的后缀部分
# substr(s,p,n) 返回字符串 s 中从 p 开始长度为 n 的后缀部分,例如 substr($1,1,5) 表示 取第一个字段的第1-5个字符
# gsub(r,s) 在整个 $0 中用 r 替代 s,相当于 sed 's///g'
# gsub(r,s,t) 在整个 t 中用 r 替代 s
# index(s,t) 返回 s 中字符串 t 的第一位置
# length(s) 返回 s 长度
# match(s,r) 测试 s 是否包含匹配 r 的字符串
# split(s,a,FS) 以 FS 为分隔符将字符串 s 分成序列 a
# sprint(fmt,exp) 返回经 fmt 格式化后的 exp
# toupper() 大写转换
# tolower() 小写转换
# systime() 返回从1970年1月1日到当前时间(不计闰年)的秒数
# strftime() 使用 C 库中的 strftime 函数格式化时间
# asort(a,b) 对数组 a 的值排序并存入数组 b,但排序后的下标改为从 1 到数组的长度
# asorti(a,b) 对数组 a 的索引排序,并把排序后的下标存入新生成的数组 b 中
# delete(a[i]) 删除数组 a 中的元素
# int() 返回截断至整数的值
# rand() 大于等于 0 且小于 1 的随机数
# strtonum(str) 将字符串转为数字
# close(...) 关闭由 print、printf 语句打开的或调用 getline 函数打开的文件或管道,如果打算写文件,并稍后在同一程序中读取,则 close 是必需的
# ...
# ——————————————————————————————————————————————————————————————————————————————————————————
# 变量不需要事先声明,变量值可以有数字和/或字符串,会自动根据上下文的不同而呈现出数字或字符串
# 数组可以用一个以上的下标来建立索引,从而实现多维数组,但本质上还是一维
# 假设当前输入记录为 "1|2|3|4|",FS、OFS 都为 | 则此时字段数为 4(NF为4)
# 如果执行 $10 = "abc" 则会创建 $5、$6、$7、$8、$9、$10 变量,其中除了 $10 为指定的值 "abc" 以外其它变量 $5 到 $9 都是空串
# 并且 NF 自动改为 10,$0 也被改为从 $1 到 $10 对应的值 1|2|3|4||||||abc
# exit 语句执行时首先(按照在代码中出现的顺序)调用所有 END 模式的操作,然后以 Expression 参数指定的退出码来终止 awk,如果 exit 出现在 END{} 中则不调用后续操作
# next 语句停止处理当前记录,继续处理下一个记录
# ——————————————————————————————————————————————————————————————————————————————————————————
# 可以使用 SHELL 重定向符实现输出重定向,下例若第1个域的值等于 100 则将其追加到文件中
awk '$1=100{print $1 > "output_file"}'
# 文件读入可放于前面
< filename awk '{print NR}'
# 求和
awk '{sum+=$1}END{print sum}'
# 平均
awk '{sum+=$1}END{print sum/NR}'
# 最大值
awk 'BEGIN{max=0}{if($1>max){max=$1}}END{print max}'
# 最小值
awk 'BEGIN {min=9999999} {if($1<min){min=$1}}END{print min}'
# 随机数
awk 'BEGIN{srand();R=int(100*rand());print R;}'
# 传递变量给 awk
varName=123 && awk -vX=${varName} 'BEGIN{print X}'
# printf是bash命令,也是awk函数,其风格与 C 相同
awk 'BEGIN{printf("%8.3f %8.3f %8.3f",a,b,c)}'
# 遍历外部数组
awk -f 'BEGIN{for(i=1;i<ARGC;i++)print ARGV[i]}' ${extarr[@]}
# 根据第 6 列进行去重操作
awk '!arr[$6]++' file
# 计算次数
awk '{name[$0]+=$1};END{for(i in name) print i,name[i]}'
# 输出奇数行
awk 'NR%2' file
awk 'i=!i' file
# 若两域相加大于 100 则输出
awk '$1+$2<100'
# 输出匹配行的下一行
seq 10 | awk '/4/{getline;{print $0}}'
# 每三行添加一个换行符或内容
awk '$0;NR%3==0{printf "\n"}'
awk '{print NR%3?$0:$0"\n"}'
sed '4~3s/^/\n/'
# 判断
awk '{print ($1>$2)?"第1排"$1:"第2排"$2}'
awk '{max=($1>$2)?$1:$2; print max}'
awk '{if($6>50){count++;print $3}else{x+5;print $2}}'
# 判断
awk '{
gsub(/\$/,"");gsub(/,/,"");
if ($4>1000&&$4<2000) c1+=$4;
else if ($4>2000&&$4<3000) c2+=$4;
else if ($4>3000&&$4<4000) c3+=$4;
else c4+=$4; }
END{printf "c1=[%d];c2=[%d];c3=[%d];c4=[%d]\n",c1,c2,c3,c4
}"'
# 循环
awk '{i=1;while(i<=NF){print NF,$i;i++}}'
awk '{for(i=1;i<=NF;i++){print NF,$i}}'
# 按第2和第3列,删除重复的,仅保留一行
awk '!arr[$2$3]++'
# 输出两个文件中第1列相同的行
awk -F',' 'NR==FNR{a[$1]=$0;next}NR>FNR{if($1 in a)print $0"\n"a[$1]}' 1.log 2.log
# 可以指定多个列分隔符,支持正则
awk -F'[:|]' '{print $2}'
awk -F'[ ]+' '{print $9}'
awk -F'[ :]+' '{print $NF"\t"$(NF-2)}'
# 按某个位置的字符分隔的方法
awk -F":" '{for(i=1;i<=3;i++)printf("%s:",$i)}'
awk -F':' '{print $1 ":" $2 ":" $3; print $4}'
awk -F':' '{print $1 ":" $2 ":" $3; for(i=1;i<=3;i++)$i=""; print}'
# 字符串分割
awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}'
# 执行命令并判断返回状态
awk 'BEGIN{if(system("grep root /etc/passwd &>/dev/null")==0)print"yes!";}'
# 将多行转多列
awk '{for(i=1;i<=NF;i++) a[i,NR]=$i } END{ for(i=1;i<=NF;i++) {for(j=1;j<=NR;j++) printf a[i,j] " ";print ""}}'
# 统计连接个数
netstat -an|awk -v A=$IP -v B=$PORT 'BEGIN{print "Clients\tGuest_ip"}$4~A":"B{split($5,ip,":");a[ip[1]]++}END{for(i in a)print a[i]"\t"i|"sort -nr"}'
# 两文件匹配
awk 'BEGIN{printf "what is your name?";getline name < "/dev/tty" } $1 ~name {print "FOUND" name " on line ", NR "."} END{print "see you," name "."}' file
# break
for(x=3;x<=NF;x++){
if ($x<0) {print "Bottomed out!"; break}
}
# continue
for(x=3;x<=NF;x++){
if ($x==0) {print "Get next item"; continue}
}
# 小于60直接跳过,不做处理
{
if ($4<60)
next
print $0
}
# 函数可以接受以逗号分隔的多个参数,参数不是强制性的,另外自定义函数不需要放在调用者之前,它可以放在任何地方,如果有返回值也直接使用 return
# function function_name(argument1, argument2, ...)
# {
# body ...
# }
# 定义可传值函数
awk '
function fmt(FMT) {
Nfmt=FMT
gsub(/[0-9]+%/, "%", FMT)
gsub(/%.*[a-zA-Z]/, "", Nfmt)
for(i=1; i<=Nfmt; i++) txt=txt FMT
return txt
}'
# 通过 exit 实现达到某条件时退出,但仍执行 END 操作
awk '{gsub(/\$/,"");gsub(/,/,""); if($4>3000&&$4<4000){exit}else{c4+=$4}};END{printf "c1=[%d];c2=[%d];c3=[%d];c4=[%d]\n",c1,c2,c3,c4}"'
# 通过 next 实现达到某条件时跳过该行,对下一行执行操作
awk '{gsub(/\$/,"");if($4>3000){next}else{c4+=$4}} END{printf "c4=[%d]\n",c4}"'
# 把三个文件的内容全部写到 fileall
awk '{print FILENAME,$0}' file1 file2 file3 > fileall
# 把合并后的文件重新分拆为三个文件,内容与原文件一致
awk ' $1!=previous {close(previous);previous=$1} {print substr($0,index($0," ") +1)>$1}' fileall
# 通过管道把命令执行结果送给 getline 并赋给变量 d 然后打印
awk 'BEGIN{"date"|getline d; print d}'
# 通过 getline 交互输入 name 并显示
awk 'BEGIN{system("echo \"Input your name:\\c\""); getline d;print "\nYour name is",d,"\b!\n"}'
# 输出包含 050x_ 的用户名
awk 'BEGIN{FS=":";while(getline < "/etc/passwd" > 0){if($1~"050[0-9]_") print $1}}'
# 显示文件的全路径
type file | awk -F "/" '{for(i=1;i<NF;i++) {if(i==NF-1){ printf "%s",$i } else { printf "%s/",$i }}}'
# 用空字符串替换 $ 符号和 , 符号再将结果输出到文件
awk 'gsub(/\$/,"");gsub(/,/,""); cost+=$4; END{print "The total is $" cost > "filename"}'
# 取得文件第1个域的最大值
awk 'BEGIN {max=100;print "max=" max}{max=($1>max?$1:max);print $1,"Now max is "max}'
# syntax1?syntax2:syntax3
if (syntax1)
syntax2
else
syntax3
# 显示日期
awk 'BEGIN {
for(j=1;j<=12;j++)
{
flag=0;
printf "\n%d月份\n",j;
for(i=1;i<=31;i++)
{
if (j==2&&i>28) flag=1;
if ((j==4||j==6||j==9||j==11)&&i>30) flag=1;
if (flag==0) {printf "%02d%02d ",j,i}
}
}
}'
# ——————————————————————————————————————————————————————————————————————————————————————————
awk '/101/' # 输出包含101的行
awk '/101/,/105/' # 101~105行
awk '/root/,/mysql/' #
awk '$1>=5&&$2=="good"' #
awk '$1*$2>100'
awk '$2>5&&$2<=15'
awk '$1 !~ /ly$/' # 显示所有第一个字段不以 ly 结尾的行
awk '$3 < 40' # 如果第三个字段值小于 40 才输出
awk '/tom/,/suz/' # 输出 tom 到 suz 之间的所有行
awk '{print NR" "$0}' # 加行号
awk '{$1=$3=""}1' # 输出除第 1 和第 3 列之外的所有列
awk '{print NR,NF,$1,$NF,}' # 显示当前记录号、域数和每行的第一个和最后一个域
awk '/101/{print $1,$2+10}' # 显示匹配行的第一、二个域加10
awk '/101/{print $1 $2}' # 显示匹配行的第一、二个域,但显示时域间没有分隔符
df | awk '$4>1000000 ' # 通过管道符读取数据,输出第4个域满足条件的行
seq 5 | awk 'NR==2{sub('/.*/',"txt\n&")}{print}' # 在指定行的前后加一行
awk 'BEGIN{FS="[:\t|]"} {print $1,$2,$3}' # 设置输入分隔符 FS
awk -F '[ :\t|]' '{print $1}' # 按照正则表达式的值做为分隔符,这里代表空格、:、TAB、|同时做为分隔符
awk -f awkfile file # 读取 awkfile 文件中的代码进行控制
awk '$1~/101/{print $1}' # 输出第一个域匹配101的行(记录)
awk 'BEGIN{OFS="%"}{print $1,$2}' # 通过设置输出分隔符 OFS 的值来修改输出格式
awk '{$1=='Chi'{$3='China';print}' # 找到匹配行后先将第3个域替换后再显示该行(记录)
awk 'BEGIN{ while( "ls" | getline) print }'
awk '{ print $1, $2 | "sort" }'
awk 'NR==1{s=$0;next}{print s,$0}' # 把第一行内容放到每行的前面
awk -F: '$1!~/mail/{print $1}' /etc/passwd # 不匹配
awk -F, 'NF=3' # 以逗号做分隔,只输出前3列的字段(重要)
awk -F: 'NF==4' /etc/passwd # 只显示有4个字段的行
awk '$1 = 100 {print $1 >> "output_file" }' # 使用重定向符进行重定向输出
awk '/keyword/{a=NR+2}a==NR{print}' # 取关键字下第几行
awk 'gsub(/liu/,"aaaa",$1){print $0}' # 只打印匹配替换后的行
awk '{$1="";$2="";$3="";print}' # 去掉前三列
echo aada:aaba | awk '/d/&&/b/{print}' # 同时匹配两条件
echo Ma asdas | awk '$1~/^[a-Z][a-Z]$/{print }' # 第一个域匹配正则
awk 'length($1)=="4"{print $1}' # 字符串位数
awk '{if($2>3){system("touch "$1)}}' # 执行系统命令
awk '{sub(/Mac/,"Macintosh",$0);print}' # 用 Macintosh 替换 Mac
awk '{gsub(/Mac/,"MacIntosh",$1); print}' # 第一个域内用 Macintosh 替换 Mac
awk '{if(NR==3)F=1}{if(F){i++;if(i%7==1)print}}' # 从第3行开始每7行显示一次
awk '{if(NF<1){print i;i=0} else {i++;print $0}}' # 显示空行分割各段的行数
awk '{b[$1]=b[$1]$2}END{for(i in b){print i,b[i]}}' # 列叠加
awk '{b=a;a=$1; if(NR>1){print a-b}}' # 当前行减上一行
awk '{a[NR]=$1}END{for (i=1;i<=NR;i++){print a[i]-a[i-1]}}' # 当前行减上一行
awk 'BEGIN{ "date" | getline d; split(d,mon) ; print mon[2]}' # 将d设为数组mon,打印数组中第2个元素
awk 'BEGIN{for(n=0;n++<9;){for(i=0;i++<n;)printf i"x"n"="i*n" ";print ""}}' # 乘法口诀
cksum
# 输出文件的 CRC 校验和和字节计数(使用 CRC 算法)
cksum /etc/passwd
# 3512668765 995 /etc/passwd