cat
读取多个文件
cat file1 file2 ...
输入信息与文件混合
echo 'this is message'|cat - filename

cat -s filename # 将文本中多行空白行压缩为1行
cat filename|tr -s '\n' # 去除空白行
cat -n filename #标记行号

find
find base_path
# 列出该目录以及它的子目录的所
# ll与ls通常只能看到本路径的文件与路径,无法看到子目录中的文件,用find解决

根据文件名或者正则表达式进行匹配搜索
find path -name "xxx.txt" # 根据名称进行匹配
find path -iname "xxx.txt" # 根据名称-忽略大小写进行匹配
find . \( -name "*.sh" -o -name "log.*" \) -print # 一次性多个条件进行匹配
find path -path "xxx" # 将路径与文件作为一个整体进行匹配
find path -name "code*" 与 find path -path "*code*"的区别在于前者只找文件名为code*,而后者只要路径带code即匹配成功
find path -regex "xxxxxx" # 符合正则表达式
find path -iregex "xxxxxx" # 忽略大小写,符合正则表达式

以上的参数进行匹配时,可以用!表示否定。即匹配不符合该条件的内容
find . \( ! -name "*.sh" -a ! -path "*log*" -a ! -path "*code*" \)

以上查找都是目录向下递归查找,如果子目录层级太多,可能文件会很多,查找变得没有意义。此时可以规定查找的深度
-mindepth 表示最低多少层往下查找,-maxdepth表示最多查找多少层级

find . -mindepth 2 -type f -print
# type表示文件类型 f表示普通文件,d表示目录,l表示链接,c字符设备,b块设备,s套接字,p表示fifo
shell进行匹配时会先将符合条件1的结果都找到,再匹配第二个条件,依此类推。所以-maxdepth或者-mindepth可以尽量在前,它能缩小查找范围。

根据时间查找
-atime 用户最近一次访问时间
-mtime 文件内容最后一次被修改的时间
-ctime 文件元数据
参数以整天数给出
find . -atime 7 # 用户访问距离现在恰好7天;+7表示超过7天,-7表示最近7天即小于7天
-amin -mmin -cmin都表示分钟

基于文件大小搜索
find . -size 2k # c表示字节,w表示字即2字节,b表示块512字节,k千字节,M,G
基于文件权限
find . -perm 644
基于用户名或者UID
find . -user root # 与find . -user 0 等效

结合find执行命令或动作 -exec,适合批量处理某些文件
任务:将某位用户(比如root)的全部文件所有权更改为另一个用户:
find . -type f –user root –exec chown slynux {} \; #{}与-exec结合使用 表示find到的每一个文件,后面的\;是固定格式
find . -name "*.sh" -exec chmod 774 {} \;
find . -name "*.sh" -exec cat {} \;>./script.learn.log

关于find命令结合-prune排除指定目录/文件的用法
两种写法:
find . -name "*.sh" -prune -o -type f -print
# 注意:
# 1.如果是-a只会输出前面的结果,即prune会返回一种表示执行失败(实际prune成功)的结果,-a后续不会执行;
# 2.另外不加print表示整体隐形的print,输出的结果为不排除给定部分的结果输出
find . ! \( -name "*.sh" -prune \) -type f
# 可以加-a,也可以不加,结果相同
# 可以加print,也可以不加,结果相同
# 如果加-o,那么只会输出前半部分的结果,即整体(不排除指定的部分)
☆ 此处感觉对于单纯命令和带print命令的区别不太理解,对于这部分的实现逻辑也不清楚。

xargs
cat example.txt |xargs # 多行输入行尾的\n被解释为一个空格,多行合为一行
cat example.txt |xargs -n 2 # 新合成的行每行保留2个字符串,超过2个换行
cat example.txt |xargs -d 'x' # 新合成的行以'x'作为分隔符号换行。默认情况以IFS作为输入定界符

cat args.txt| xargs -n 1 cmd # 一个一个将args.txt中的行内容喂给cmd
如果cmd有多个参数,例如 cmd -p args -l,可以考虑下面的写法进行替换
cat args.txt| xargs -I {} cmd -p {} -l # 注意关键参数为大写的I

find与xargs结合使用
为了避免xargs误会行内容的空格为定界符,需要使用print0与find结合,以字符null作为分隔输出。
find source_code_path -type -f -name "*.java" -print0 | xargs -0 wc -l # xargs -0将以“\0”作为定界符

场景使用:
执行一些来自stdin的多个参数的命令,可以采用子shell妙招
cat files.txt | (while read arg; do cat $arg;done) # 管道前模拟来自stdin的多参数命令,后续子shell的用法仔细体会
也可以尝试使用xargs来进行处理
cat files.txt | xargs -I {} cat {}

tr(translate)
字符替换,删除以及压缩。一般用法为 tr [参数] set1 set2。

将来自stdin的输入字符从set1映射到set2,并将输出写到stdout。两个映射的set为字符集。如果set1.length>set2.length,那么set2用最后一个字符不断复制达到与set1长度相同; 如果set1.length<set2.length,则set2长度超过的部分无效。

集合的定义('起始字符-终止字符')
'A-Z0-9' 'A-FN-X' '0-9'如果不是一个连续的字符序列,那就只包含了三个元素,等价于('起始字符' '-' '终止字符')

可以使用一定的算法对字符替换达到加密的效果,而后再替换回来达到解密的效果
echo 12345 | tr '0-9' '9876543210' #Encrypted
echo 87654 | tr '9876543210' '0-9' #Decrypted
比较出名的ROT13加密算法,加密和解密都使用同一个函数。
echo "hello" | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' 'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm'
# 可以试着把获得的结果使用同一个替换规则进行处理,看看结果是什么

通过指定需要删除的字符集合,将出现在stdin中的字符进行清洗:
cat file.txt | tr -d '0-9' #把文本中的数字全部剔除
echo "Hello 123 world 456" | tr -d '0-9'

补集
场景:如果在清洗文本的时候,对于需要清洗的部分,不知道如何界定字符范围,或者界定字符范围的表达非常复杂,而同时,需要保留的字符范围很简单,可以考虑补集法。
如:hello 1 charg2 33jdlsajkl 4AJKLDAUIOl 5.sjliil%%% 需要将数字提取出来:
echo hello 1 charg2 33jdlsajkl 4AJKLDAUIOl 5.sjliil%%% | tr -d -c '0-9 \n' # -c [set] 定义了一个补集,有时候表达起来会比较简洁

压缩连续重复的字符 tr -s [set]
set中的字符,只要是重复的,可以压缩为单个字符。

一些约定的,简单的字符集表达,使用时,按照 tr [:set1:] [:set2:]的格式
alnum: 字母和数字
alpha: 字母
cntrl: 控制字符(非打印字符)
digit: 数字
graph: 图形字符
lower: 小写字符
print: 可打印字符
punct: 标点符号
space: 空白字符
upper: 大写字符
xdigit: 十六进制字符
如:tr '[:lower:]' '[:upper:]'

md5sum/sha1sum
md5sum file >file.md5 # 将该文件的md5结果和文件名一起存放在file.md5中,结果是一个32个字符的十六进制串
md5sum -c file.md5 # 校验文件是否与file.md5记录的校验结果一致
md5sum *.md5 # 校验所有的md5文件

对一个目录中所有文件以递归的方式进行校验
md5deep/sha1deep -rl path > direc.md5
也可以用find+xargs的方式:
find path -type f -print0 | xargs -0 md5sum >> direc.md5
md5sum -c direc.md5

排序、单一与重复
sort可以对文本文件与stdin进行排序操作,从stdin中获取输入,将输出写入stdout。
uniq是个经常与sort一同使用的命令,uniq可以从文本和stdin中提取不重复的行(重复的行只输出一次)。

sort file1.txt file2.txt .. > sorted.txt # 将这些文件的内容提取并进行排序后输出到sorted.txt中
sort file1.txt file2.txt .. -o sorted.txt # 效果相同

cat sorted_file.txt | uniq> uniq_lines.txt # 将不重复的内容提取到文件中

sort -n file.txt # 按照数字排序
sort -r file.txt # 按照逆序排序
sort -M months.txt # 按照月份排序
sort -C sorted.txt # 查看是否已经完全排序
如果需要检查是否用数字进行过完全排序:
sort -nC sorted.txt

sort -m sorted1.txt sorted2.txt

-k 表示依据哪一列进行排序,对表单格式的文本有效果
sort -nrk 1 data.txt # 对文本第一列按照数字逆序排列
对于-k参数要注意,如果文本的数据是比较整齐的列,可以用此排序;如果不是,小心它对比的列到底是该行里的什么位置的字符,对于只有一列的,如果排序按照第二列排序,那么没有第二列的会被排在最靠前。

sort -z data.txt | xargs -0 # 使sort输出 与 以‘\0’结尾的xargs命令相兼容

-d指明以字典序排序
-b忽略文件中的前导空白字符串

uniq可以将连在一起的重复行处理为单一行,如果需要所有文本都是不重复的,需要与sort搭配使用。
cat uniq1.txt |uniq # 只能处理连续重复的行
sort uniq1.txt |uniq # 保证整个文本内容不重复

uniq其它用法:
uniq -u sorted.txt # 显示内容中没有出现重复的行
uniq -c sorted.txt # 统计各行在文件中出现的次数
uniq -d sorted.txt # 显示内容中重复的行
-s 2 表示跳过前两个
-w 2表示只取2个字符进行比较
sort data.txt | uniq -s 2 -w 2

将命令输出作为xargs命令输入的时候,最好为输出的各行添加一个0值字节终止符。在将uniq命令的输入作为xargs的数据源时,同样如此。例如,stdin的文本行中,This is a line 是一个单行,但是xargs会认为是4个不同的参数,但只是一个单行而已。如果使用0作为终止符,那么\0就被作为定界符。使用-z命令生成包含0值字节终止符的输出:
uniq -z file.txt|xargs -0 rm

临时文件命名与随机数
编写脚本时临时存储的文件,最好放在/tmp,该目录下的文件会在系统重启时被清空
如果有tempfile这个命令,可以直接用该命令生成临时文件名
echo ${tempfile} # /tmp/fileawm8y
如果没有安装tempfile命令,可以使用$RANDOM或者$$
temp_file="/tmp/file-$RANDOM" #用随机数作为临时文件名后缀
temp_file="/tmp/xxx.$$" # 用.$$作为添加的后缀,会被扩展成当前运行脚本的进程ID

分割文件和数据
split -b 10k data.file # 每个文件大小10k,分割这个文件。k,G,M,c(byte),w(word)
split -b 10k datafile -d -a 4 # 分割出来的文件以数字为后缀,且数字长度为4
split -l 10 data.file # 分割文件不以大小,而是以行数
split [COMMAND_ARGS] prefix # 最后一个参数表示分割文件的前缀名
split -b 10k datafile -d -a 4 splited_file # 分割的文件名都以“splited_file”打头

csplit是split的一个变体,可以根据文本的自身特点进行分割,是否存在某个单词或者文本内容都可以作为分割条件。

根据扩展名切分文件名
看一个不用分割字符串,直接获取到文件的名称和后缀名的例子
file_jpg="sample.jpg";name=${file_jpg%.*};echo file name is : $name # 获取文件名称
file_jpg="sample.jpg";extension=${file_jpg#*.};echo extension is : $extension # 获取后缀名称
注意%和%%的不同,前者是非贪婪操作,只要匹配成功,即将符合条件的内容输出,停止匹配;后者是贪婪操作,会一直匹配到不符合要求的内容为止:
file_jpg="ex.sample.jpg";name=${file_jpg%.*};echo file name is : $name
file_jpg="ex.sample.jpg";name=${file_jpg%%.*};echo file name is : $name
${VARxy},var表示变量名称,x表示百分或井号,y表示匹配表达式;
百分查右,右侧完全匹配则删右;井号取左,左侧完全匹配则去左
贪婪模式下,删除掉能够匹配的最大结果

批量重命名和移动
综合运用:
#!/bin/bash
#Filename: rename.sh
#Description: Rename jpg and png files
count=1;
for img in *.jpg *.png
do
new=image-$count.${img##*.}
mv "$img" "$new" 2> /dev/null
if [ $? -eq 0 ];
then
echo "Renaming $img to $new"
let count++
fi
done

也可以用rename来批量操作重命名:
rename *.JPG *.jpg
rename 's/ /_/g' * # 将文件名中的空格替换成字符"_"
rename 'y/A-Z/a-z/' *

拼写检查
/usr/share/dict/下包含了一些词典文件。可以利用这个列表来检查某个单词是否为词典中的单词。

交互输入自动化
场景1:如何能够把脚本运行时需要的内容提前用命令或者脚本传输送入?
#!/bin/bash
#Filename: interactive.sh
read -p "Enter number:" no ;
read -p "Enter name:" name
echo You have entered $no, $name;
将需要的输入用stdin的形式传入,用\n表示Enter键。
echo -e "1\nhello\n" | ./interactive.sh # 结果:You have entered 1, hello
或者
./interactive.sh < input.data

场景2:脚本随机产生需要输入的内容,此时如何使用命令来提供脚本需要的内容?
yum install expect

#!/usr/bin/expect #注意这里不是/bin/bash,除了给与该脚本权限,还需要用./的方式执行,不能用sh
#Filename: automate_expect.sh # 通过检查输入提示来发送数据
spawn ./interactive .sh # 指定需要自动化哪一个命令
expect "Enter name:"
send "hello\n"
expect "Enter number:"
send "1\n" # 与expect一起等待消息,发送需要输入的内容
expect eof # 明确命令交互结束

posted on 2021-06-06 09:20  长江同学  阅读(64)  评论(0编辑  收藏  举报