如何基于文件名创建目录并迁移同名不同格式的文件至对应目录
嘿,刚上手shell脚本不用焦虑,我来帮你拆解你写的这段代码逻辑,顺便揪出里面的小问题,再给你优化下~
先看你写的脚本逻辑
首先把你的代码贴出来:
#!/bin/bash for f in ./*.txt ./*.conf ; do [[ -e "$f" ]] dir="${f%.*}" if [ ! -d "$dir" ] ; then mkdir "$dir" fi mv "$f".* "$dir" done
我逐行给你解释:
for f in ./*.txt ./*.conf ; do:遍历当前目录下所有.txt和.conf后缀的文件,每找到一个文件,就把它的完整路径(比如./file1.txt)赋值给变量$f。[[ -e "$f" ]]:检查当前$f对应的文件是否存在。不过其实如果目录里没有这类文件,for循环根本不会执行,所以这行有点多余,但也不会出错。dir="${f%.*}":这是shell里的参数扩展技巧,%.*的意思是从$f的末尾开始,删掉第一个.以及后面的所有内容。比如$f是file1.txt,处理后dir就变成了file1;如果是file2.conf,dir就是file2,这一步就是提取不带扩展名的文件名,用来当目录名。if [ ! -d "$dir" ] ; then mkdir "$dir"; fi:检查这个目录是否不存在(! -d表示“不是目录”),如果确实没有,就创建这个目录。mv "$f".* "$dir":这行是你脚本里的小问题!比如当$f是file1.txt时,"$f".*会变成file1.txt.*,这可不是你想要的file1.*哦——你本来想移动所有叫file1的文件,结果现在只会找名字是file1.txt开头带其他后缀的文件,完全跑偏了。
修正&优化后的脚本
把移动那行改成用$dir(也就是不带扩展名的前缀)来匹配文件,再优化下避免重复处理(比如file1.txt和file1.conf会被循环两次,第一次就已经把所有file1.*移走了,第二次处理file1.conf时文件已经不在了):
#!/bin/bash # 先提取所有唯一的文件名前缀,避免重复处理 for prefix in $(ls -1 ./*.txt ./*.conf | sed 's/\.[^.]*$//' | sort -u); do # 检查目录是否存在,不存在则创建 if [ ! -d "$prefix" ]; then mkdir "$prefix" fi # 移动所有以该前缀命名的文件到对应目录 mv "$prefix".* "$prefix" done
这个优化版的逻辑更清晰:
ls -1 ./*.txt ./*.conf:把所有目标文件按行列出;sed 's/\.[^.]*$//':去掉每个文件名的扩展名,得到前缀;sort -u:对前缀去重,确保每个前缀只处理一次;- 后面的创建目录、移动文件就和你原来的逻辑一致,但这次用
$prefix.*就能准确匹配所有同名不同扩展名的文件啦。
新手小提醒
- 一定要用双引号包裹变量(比如
"$f"、"$dir"),不然如果文件名里有空格、特殊字符,脚本会直接报错,你原来的脚本这点做得很对! - 如果怕误操作,可以先把
mv改成echo mv,先预览下要移动的文件,确认没问题再改成真正的mv。
内容的提问来源于stack exchange,提问作者Bill
相关产品推荐
相关产品推荐

