起因
在linux平台使用chrome浏览器的时候使用的是浏览器默认的下载器,所以所有的下载文件都放在了~/download 目录下面,久而久之这个目录下面充斥着各种文件。其中包含下载的图像、程序的源码包、各种电子书还有很多用来测试的视频序列。最开始的时候我是使用这样的命令来整理不同的类型文件的:
1 2 3 4 mkdir pdf compress imagesmv *.pdf ./pdfmv *.zip *.gz *.7z ./compressmv *.jpg ./images
但是这样有一个问题,我要自己判断文件的类型,然后放到对应的位置,如果要整理其他路径下面的文件还要重新输入命令,所以就产生了自己写一个工具来整理文件的想法。
已经完成的脚本在 https://github.com/diandianti/move_it
实现过程
实现按照类型分类文件的工具可以用c、python或者shell,权衡了一下实现的难度以及我的需求,最后使用shell来实现。
文件类型获取
文件类型使用文件的扩展名来判断,获取扩展名的方式如下:
1 2 file_path=/path/to/file.test ext_name=${file_path##*.}
获得了扩展名之后需要判断文件的类型,是文档还是图片或者是压缩文档,我写了一个函数来实现这个功能。主要思路是创建了一个数组,然后数组里面包含了类型的名字,让后让输入的扩展名来和类型包含的名字来比对,如果一致就返回当前的类型,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 mi_compress=(zip tar gz 7z tgz arc arj taz \ lha lz4 lzh lzma tlz tzo t7z z dz \ lrz lz lzo xz zst tzst bz2 bz tbz tbz2 \ iso) mi_image=(jpg jpeg bmp png ppm\ gif pbm pgm tga xbm tif tiff \ svg svgz psd) mi_video=(mkv webm mjpg mjpeg m2v ogm m4v \ mp4v vob qt nuv wam rm rmvb flv avi\ yuv mp4) mi_audio=(mp3 flac aac mid midi wav) mi_doc=(doc docx xps md txt ps diff) mi_excel=(xls xlsx csv) mi_ppt=(ppt pptx) mi_font=(ttf otf) mi_code=(sh bash py c cpp cc cxx h hpp s) mi_web=(html css js) mi_ebook=(mobi epub pdf) mi_nn=(caffemodel onnx prototxt pb) mi_bin=(deb appimage bin dat) mi_apk=(apk) mi_lib=(so a) mi_all_ff=(mi_compress mi_image mi_video mi_audio mi_doc mi_excel \ mi_ppt mi_font mi_code mi_web mi_ebook mi_nn mi_bin mi_apk mi_lib) get_file_type () { if [ $# -ne 1 ];then echo "others" return 0 fi ext_name=${1} for ff in ${mi_all_ff[@]} do eval ffs=\( \${${ff} [@]} \) for i in ${ffs[@]} do if [ "${ext_name} " == "${i} " ]; then echo "${ff:3} " return 0 fi done done echo "others" return 0 }
文件处理
在核心的文件类型获取功能实现之后就可以处理文件了。主要思路是获取文件类型,判断结果目录是否存在,最后移动文件,代码如下:
1 2 3 4 5 6 7 8 9 10 11 mi_process_file () { fn=$(basename ${1} ) ext_name=${1##*.} ft=$(get_file_type ${ext_name,,} ) mi_info "${1} -> ${2} /${ft} " ls ${2} /${ft} > /dev/null 2>&1 || mkdir -p ${2} /${ft} mv ${1} ${2} /${ft} }
自定义后处理脚本
在文件移动之后我还想做一些其他的操作,比如把所有的压缩文件解压缩,或者把所有的图像上传到图床,所以添加了一个可以后处理的操作。在处理之后脚本会检测名为 mi_${type}_post的函数是否存在,如果存在那么就用这个函数做后处理,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 mi_process_file () { fn=$(basename ${1} ) ext_name=${1##*.} ft=$(get_file_type ${ext_name,,} ) mi_info "${1} -> ${2} /${ft} " ls ${2} /${ft} > /dev/null 2>&1 || mkdir -p ${2} /${ft} mv ${1} ${2} /${ft} if [ "$(type -t mi_${ft}_post) " == function ]; then pushd ${2} /${ft} > /dev/null 2>&1 mi_info "Post process ${fn} with mi_${ft} _post!" mi_${ft} _post ${fn} popd > /dev/null 2>&1 fi }
参数解析
作为一个程序需要能够解析从终端输入的参数,我使用的是getopts命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 parse_arg () { while getopts :vVhRnd: opt do case "$opt " in v) let log_level=log_level+1 ;; d) out_path=$OPTARG ;; n) let process_dir=0 ;; R) let recursion=1 ;; V) help ;; h) help ;; *) ;; esac done shift $[ $OPTIND - 1 ] for param in "$@ " do all_todo+="${param} " done }
如何配置
因为整个脚本才200多行,所以要修改配置直接修改文件即可。如果要添加一个新的类型和新的文件扩展名只需要这样添加即可:
1 2 3 4 5 6 7 8 9 10 11 mi_compress=(zip tar gz 7z tgz arc arj taz \ lha lz4 lzh lzma tlz tzo t7z z dz \ lrz lz lzo xz zst tzst bz2 bz tbz tbz2 \ iso) ... ... mi_lib=(so a) +mi_test=(test1 test2) mi_all_ff=(mi_compress mi_image mi_video mi_audio mi_doc mi_excel \ - mi_ppt mi_font mi_code mi_web mi_ebook mi_nn mi_bin mi_apk mi_lib mi) + mi_ppt mi_font mi_code mi_web mi_ebook mi_nn mi_bin mi_apk mi_lib mi_test)
如果要实现某种类型的后处理,直接在文件中添加相关的函数即可:
1 2 3 mi_test_post() { echo "This post process of test type" }
如果要修改默认的文件存放位置,直接修改变量config_def_path即可。