原文链接:http://defsniky.com/posts/2014-01-28-using-sed-and-awk-format-file-name.html
1. 需求
将文件名统一整理成如下格式:
1)文件名中只允许出现英文字母、数字以及短划线;
2)年份开头,并以短划线连接文件名,如:2014-Title of File.pdf;
3)四个字母及以上或短划线引导的单词首字母大写,出现其它符号如冒号、顿号等以空格代替。
搜集文献的时候为了尽快、更多地下载,往往不想费时间整理文件名,于是就会得到下面的结果:
根据文题及发表时间重命名后,不同的出处的文档标题格式各异,且各种符号不一而足,因而需要按照需求统一格式,下面引入 sed 与 awk 的解决方案,一行代码
解决问题*_*
2. 解决方案
sed 与 awk 相关教程见此处:CoolShell>AWK 简明教程、CoolShell>sed 简明教程。由于文件名是单行文本,sed 只做单行文本的正则匹配与更改,即用到's/old/new/g;'
将old
替换为new
,用于修改一些多余的符号包括空格、冒号等;awk 则是对输入流进行格式化处理,得到我们需求中规定的格式。
sed 部分正则替换代码如下:
sed 's/[ ]*:[ ]*/-/g;' #冒号(包括两边空格)替换为短划线
sed 's/\./=/g;' #将点号临时替换为=
sed 's/\(.*\)=/\1./g;' #将括号临时替换为=
sed 's/[ ]*[+|?|_|,|;][ ]*/ /g;' #特殊符号替换为空格
sed 's/=/ /g;' #将临时=替换为空格
sed 's/ \([0-9]\)/-\1/g;s/\([0-9]\) /\1-/g' #将数字间的空格替换为短划线
awk 按照首字母大写规则进行格式化输出:
#以短划线分割 对短划线引导的单词首字母大写
awk -F- '{for(i=1;i<=NF;i++){$i=tolower($i);sub(".",toupper(substr($i,1,1)),$i)}}1' OFS=-
#四个字母以上单词首字母大写
awk '{for(i=1;i<=NF;i++){if(length($i)>3||i==1){sub(".",toupper(substr($i,1,1)),$i)}}}1'
以pipe
连接所有处理过程(gist):
#!/bin/bash
#Script name: Renamee.sh
mv "$1" "`basename "$1"|sed 's/[ ]*:[ ]*/-/g;s/\./=/g;s/\(.*\)=/\1./g;s/[ ]*[+|?|_|,|;][ ]*/ /g;s/=/ /g;s/ \([0-9]\)/-\1/g;s/\([0-9]\) /\1-/g'|awk -F- '{for(i=1;i<=NF;i++){$i=tolower($i);sub(".",toupper(substr($i,1,1)),$i)}}1' OFS=-|awk '{for(i=1;i<=NF;i++){if(length($i)>3||i==1){sub(".",toupper(substr($i,1,1)),$i)}}}1'`"
如需批量操作可用Mapwalk。
3. 待改进
- 以单词长度作为首字母大小写的判断仍不够智能,一些较长的介词仍会被误判而一些首字母缩写的单词(如 BOLD)则会被误杀;
- 从 PDF 中直接解析年份与文题一直悬而未解,能找到合适的方法才可以真正完全自动化;
- ...