我有一个包含100,000
文件的目录。这些是我需要移动到三个不同目录的音频文件train
,dev
和test
。分别按80%
、10%
和的顺序10%
。
mv `ls | head -500` ./subfolder1/
如果我们知道默认数量但不知道文件总数的百分比,则这会移动文件。我想知道是否有一种更简洁的方法将 dir 分成三个。
答案1
ls
使用 的输出作为输入通常不是一个好主意。
您可以通过一个小脚本来实现您想要的:
#! /bin/sh
# file counter
cnt=0
# for each file (replace *.* by *.mp3 to restrict to some files)
for i in *.*
do
# create a number for 0 to 9 from the counter
a=$(( cnt%10 ))
# for 8 files on 10,
if [ $a -lt 8 ]
then
# move file to train folder (think to remove `echo`)
echo mv "$i" train/
# for one file on 10 (a is 8)
elif [ $a -lt 9 ]
then
# move file to dev folder (think to remove `echo`)
echo mv "$i" dev/
# for one file on 10 (a is 9)
else
# move file to test folder (think to remove `echo`)
echo mv "$i" test/
fi
# and update the counter
cnt=$((cnt+1))
done
答案2
使用如下 shell bash
:
#!/bin/bash
# Get all names.
# This assumes that *.mp3 matches only the things that we'd like to move.
names=( *.mp3 )
# Create our destination directories.
mkdir train dev test
# Calculate some numbers...
n=${#names[@]} # 100% of the files
# Six files at least are needed...
# (or one of the directories will be empty)
if [ "$n" -lt 6 ]; then
printf 'Only %d files\n' "$n"
exit 1
fi
n80=$(( (80*n)/100 )) # 80% of the files
n10=$(( (n - n80)/2 )) # 10% of the files
# Move the files...
mv "${names[@]:0:n80}" train # Move the 80%
mv "${names[@]:n80:n10}" dev # Move the 10%
mv "${names[@]:n80+n10}" test # Move the rest
这会读取我们想要移动到名为 的数组中的文件的名称names
。假设*.mp3
使用的模式将匹配仅有的和全部我们感兴趣的名称(修改此模式以满足您的需要)。
然后计算该数组的 80% 和 10% 长度。
文件的移动是使用数组切片(在bash
)中完成的。切片是从length 的${arr[@]:offset:length}
从零开始的偏移量开始的切片。如果缺少参数(如最后一次调用),切片将运行到数组末尾。offset
length
length
mv
由于我们还没有准备好将文件分成两部分(整数算术),因此每个目录中最终的文件数量显然会有点近似。如果文件数不能整除,则该test
目录可能会多获得一个文件。dev
这还依赖于文件名足够短,以便在一次操作中可以移动 80% 的文件。如果不是这种情况,您必须将最后三行(行mv
)更改为
for name in "${names[@]:0:n80}"; do
mv "$name" train
done
for name in "${names[@]:n80:n10}"; do
mv "$name" dev
done
for name in "${names[@]:n80+n10}"; do
mv "$name" test
done