我有一个目录,里面装满了各种文件,这些文件的名称不同(即没有使用特定模式命名)且具有不同的扩展名,我想将每个文件放在以每个文件命名的新创建的子目录中;在 Linux 下从命令行实现此目的的最佳方法是什么?
这听起来有点令人困惑,让我举个例子:让我们在目录中随机调用一个文件./filename.ext
,我想将其放在一个名为的子目录中./filename
,这样新路径实际上就是./filename/filename.ext
。
我按照以下步骤进行了一些尝试:
- 我在测试目录中创建了一些测试文件,从
file-1.txt
到file-9.txt
for num in {1..9}; do touch file-$num.txt; done
- 我创建了一个以每个文件名命名的目录
for name in $(eval ls | cut -b 1-6); do mkdir $name; done
- 我已将源文件移动到各自的目录中
for name in $(eval ls | grep -e ".txt" | cut -b 1-6); do mv $name.txt $name/$name.txt; done
如您所见,此解决方案有效,但它的巨大缺点是它只在这种情况下有效,即文件名长度和扩展名完全相同的文件。如果我有一些文件的名称和扩展名不同,那么这根本没用。cut
我想,使用命令在这里不是理想的解决方案,但目前我还没有找到更好的方法。
作为奖励,如果能找到一种在移动/重命名文件时自动创建子目录的方法,而无需mkdir
先前使用(因此当我ls
实际重命名时,不必担心排除新创建的目录),那就太酷了;但最终这是一个次要问题。
答案1
我想你的问题的解决方案叫做参数替换(看看详细说明)。给定一个文件的名称,filename
您将使用 获得其扩展名${filename##*.}
,并使用 获得不带扩展名的名称${filename%.*}
。
也就是说,您可能需要修改for
循环,例如:
# for all (*) files in the current directory
for i in *;
do
# -f checks if it is a file (skip directories)
[ -f "$i" ] || continue
# store the file name in filename
filename=$(basename $i)
# ext = the extension of the file (here we don't care, jfi)
ext="${filename##*.}"
# dir = the file name without its extension
dir="${filename%.*}"
# create the directory
mkdir -p $dir
# move the file in that directory
mv $i $dir
done
不幸的是,我没有明白你的意思奖金任务,因此它仍将是一个开放的挑战...:)
答案2
这是一种使用较少 shell 脚本但使用较多命令的方法。
find -maxdepth 1 -type f > file-list
查找当前目录中的所有文件并保存此列表。
grep -o '\./.*\.' file-list | sed s/\.$// > dir-list
过滤此列表以仅包含某处带有点的文件名。使用 sed 删除最后一个点,保存此列表。
mkdir $(<dir-list)
创建所有文件夹。
sort dir-list > dir-list.s
sort file-list > file-list.s
这是为了按列出的顺序将文件名与文件夹名称对齐>
paste file-list dir-list
这看起来不正确,因为文件文件列表将在这里。在我的例子中,还有一个名为随机的. 从文件列表中删除这些名称。
sed -E '/^\.\/(random|file-list)$/d' -i file-list
sort file-list > file-list.s
再次调查以下命令的输出:粘贴文件列表目录列表
它看起来应该是这样的:
./CCrtWW].GdH ./CCrtWW]
./c[ifzJlKnEYXO.wXF ./c[ifzJlKnEYXO
./FAEhz.u[A ./FAEhz
./FGMlrKcJHF.pHp ./FGMlrKcJHF
./HGxKPWZK.MpK ./HGxKPWZK
./JxwNrN.zoj ./JxwNrN
一旦看起来正确,就从列表中创建一个 shell 脚本并将其发布:
paste file-list dir-list | sed 's/^/mv -v /' | sh