我正在寻找一个 Linux 命令,可以按文件大小的升序将文件从一个目录移动到另一个目录,例如,第一个文件大小为 1 Mb,然后是 1.2 Mb,然后是 1.3 Mb 等等。
答案1
如果您要将单个目录中的文件移动到另一个单个目录中,则可以使用ls
可以按大小对文件进行排序的命令。以下脚本将按照文件大小增加的顺序将文件从源目录(作为第一个参数给出)移动到目标目录(作为第二个参数给出):
#!/usr/bin/env bash
src="$1"
dst="$2"
if [[ ! -d "$src" ]] ; then
echo "Source directory $src does not exist!"
exit 1
fi
if [[ ! -d "$dst" ]] ; then
echo "Destination directory $dst does not exist!"
exit 2
fi
cd "$src" || exit
ls -arS | while read -r f ; do
if [[ -f "$f" ]] ; then
echo mv "$f" "$dst"
fi
done
echo
一旦您确认脚本运行正常,您就可以删除该命令。
答案2
在里面壳牌(zsh
),利用其Glob 限定符,你可以这样做(从源目录中):
Withzsh
的内置函数zmv
:
% autoload zmv
%
% zmv -Q -n -- '*(.oL)' '/path/to/target/$f'
注意:该选项-n
用于试运行...当对输出满意时,用-v
(详细程度) 才能真正发生移动。
或使用外部/bin/mv
(首先,请参阅下面的试运行通知):
printf '%s\0' *(.oL) | xargs -0 mv -nv -t /path/to/target/ --
或者一次移动一个文件:
printf '%s\0' *(.oL) | xargs -0 -I {} mv -nv -- {} /path/to/target/
注意:对于试运行,你可以使用如下方法:
printf '%s\0' *(.oL) | xargs -0 stat --printf='Name: %n Size: %s\n'
位于*(.oL)
:
.
表示纯文件。o
表示按升序排序。L
表示文件的大小(长度)。
答案3
这是在源目录中运行的多行单行命令:
find -type f -printf '%s/%p\0' | # get paths with sizes together into safe zero-delimited lines
sort -zn | # do numeric sort (ascending)
cut -zd/ -f2- | #cut the sizes down
xargs -0 cp -v --parents --target-directory="../B/" # do the copy
笔记:
- 不要忘记
cd path/to/source/dir
。 "../B/"
用目标目录的相对路径或绝对路径替换。- 文件名可以包含任何字符,包括空格、换行符
$%^<>""
和其他棘手的内容。 - 它保留路径,在目标上创建必要的子文件夹。
- 可以省略
-v
以保持cp
沉默。 - 元数据未保留,
cp
请使用--preserve=all
。 - 此脚本复制文件,而不是移动文件。原因是:
- 没有
mv --parents
命令,我懒得模仿它。 - 在一个文件系统中,您可以简单地将整个源目录重命名为目标,这使得文件被“移动”瞬间。但是,无论如何,移动至其他文件系统都是通过复制+删除源序列完成的。
以下是我理解您的数据集/创建测试数据的方式:
# making test dirs
mkdir test/{,A,B}
cd test/A
mkdir sub{1..4} sub1/sub{1..2}
# making test file of random sizes
find -mindepth 1 -type d -exec sh -c 'cd "$1"; x=${RANDOM}0; dd if=/dev/urandom of=${RANDOM}.${x}.bin count=${x}' - {} \;
$ tree -s .. # review
..
├── [ 0] A
│ ├── [ 0] sub1
│ │ ├── [ 89502720] 5334.174810.bin
│ │ ├── [ 0] sub1
│ │ │ └── [ 126310400] 24545.246700.bin
│ │ └── [ 0] sub2
│ │ └── [ 124303360] 17288.242780.bin
│ ├── [ 0] sub2
│ │ └── [ 149780480] 22029.292540.bin
│ ├── [ 0] sub3
│ │ └── [ 9246720] 19263.18060.bin
│ └── [ 0] sub4
│ └── [ 110320640] 31098.215470.bin
└── [ 0] B
8 directories, 6 files
清单:
$ find -type f -printf '%s/%h/%f\0' | sort -zn | cut -zd/ -f2- | tr '\0' '\n' | xargs -l ls -lh
-rw-r--r-- 1 user group 8.9M Aug 7 14:31 ./sub3/19263.18060.bin
-rw-r--r-- 1 user group 86M Aug 7 14:30 ./sub1/5334.174810.bin
-rw-r--r-- 1 user group 106M Aug 7 14:31 ./sub4/31098.215470.bin
-rw-r--r-- 1 user group 119M Aug 7 14:30 ./sub1/sub2/17288.242780.bin
-rw-r--r-- 1 user group 121M Aug 7 14:30 ./sub1/sub1/24545.246700.bin
-rw-r--r-- 1 user group 143M Aug 7 14:31 ./sub2/22029.292540.bin
怎么运行的:
$ find -type f -printf '%s/%p\0' | # get paths with sizes together into safe zero-delimited lines
sort -zn | # do numeric sort (ascending)
cut -zd/ -f2- | #cut the sizes down
xargs -0 cp -v --parents --target-directory="../B/" # do the copy
./sub3 -> ../B/./sub3
'./sub3/19263.18060.bin' -> '../B/./sub3/19263.18060.bin'
./sub1 -> ../B/./sub1
'./sub1/5334.174810.bin' -> '../B/./sub1/5334.174810.bin'
./sub4 -> ../B/./sub4
'./sub4/31098.215470.bin' -> '../B/./sub4/31098.215470.bin'
./sub1/sub2 -> ../B/./sub1/sub2
'./sub1/sub2/17288.242780.bin' -> '../B/./sub1/sub2/17288.242780.bin'
./sub1/sub1 -> ../B/./sub1/sub1
'./sub1/sub1/24545.246700.bin' -> '../B/./sub1/sub1/24545.246700.bin'
./sub2 -> ../B/./sub2
'./sub2/22029.292540.bin' -> '../B/./sub2/22029.292540.bin'
答案4
您可以使用查找。
find . -size +1M
将递归地查找当前目录中每个超过 1MB 的文件。
添加后-exec
我们就可以移动文件了:
find . -type f -size +1M -exec mv "{}" large_files/ \;
可以使用 bash 脚本将其制成循环:
for size in $(seq 2 -0.1 1)
do
mkdir -p "${size}"_files
find . -type f -size +"${size}"M -exec mv {} large_files/ \;
done
这里seq
将生成 2 到 1 之间的数字,以 0.1 为增量,例如 2、1.9 等。我们必须按相反的顺序执行,因为大于 1MB 的文件也会匹配 2MB 的文件,因此使用负增量。
mkdir
将为每种大小创建一个目录,find 将查找文件并将其移动到目录中。-p
如果目录已存在,则确保不会打印任何错误。