我试图创建一个循环来按大小对每个目录中的文件进行排序,然后将最大的两个复制到另一个位置,保持目录格式(如下)。
folder/sample 1
.../s1.fastq.gz
.../s2.fastq.gz
.../s3.fastq.gz
.../s4.fastq.gz
folder/sample 2
.../s1.fastq.gz
.../s2.fastq.gz
.../s3.fastq.gz
.../s4.fastq.gz
我是 Linux 新手,所以我很挣扎。我试过:
#!/bin/bash
mkdir newfolder
for dir in folder/*
do
echo $dir
ls -S $dir/*.gz | head -n +2 | cp -T newfolder
done
但是,我收到以下错误。
cp: missing destination file operand after 'newfolder.'
如何正确地将大文件送入复制功能?
我也尝试过使用 xargs,但出现错误
xargs: invalid option -- 'w'
因为我没有正确地一次喂一根线。
答案1
zsh
对于 shell 来说,这将是一个比以下更好的选择bash
:
#! /bin/zsh -
ret=0
for dir (folder/*(/)) {
two_largest_files=($dir/*.gz(N.OL[1,2]))
if (($#two_largest_files)) {
mkdir -p newfolder/$dir:t &&
cp -v $two_largest_files newfolder/$dir:t/ || ret=$?
}
}
exit $ret
(请注意,并非所有实现-v
都支持 verbose ,如果您的实现不支持,请替换为)。cp
(set -x; cp $two...)
答案2
这是相当复杂的。首先,您不应该解析 的输出ls
,因为对于名称中带有换行符的文件,事情可能会变得混乱。因此最好在所有管道中使用 NUL 作为记录(行)分隔符。这是一个例子:
for dir in folder/*
do
echo "$dir"
find "$dir" -type f -print0 -exec du -h0 {} + | sort -hrz | head -zn 2 |
sed -z 's/^.*[[:space:]]// ' | xargs -0I@ cp -v @ newfolder
done
find
查找给定的文件"$dir"
- 您应该在此处使用引号。它还适用du
于所有文件以获取其大小。sort
按大小对结果进行排序。head
限制为前 2 个。sed
删除文件名之前的大小值。xargs
使用管道中的参数构建实际命令。
NUL 分隔符通常必须在所有命令中指示,因此 、和;z
中有标志。在和;它们是由的开关产生的。sort
head
sed
0
du
xargs
-print0
find
(我不知道你为什么-T
在 中使用该标志cp
。在我的示例中它不存在,而是-v
提供反馈。)
答案3
您的代码有两个问题:
- 永远不要尝试解析 的输出
ls
,stat
而是使用; - 当文件“很多”或文件名包含“有趣”字符(“
/sample 1/
”)时,请使用find
和xargs
。请参阅man find
和man xargs
了解更多信息。
做类似的事情:
mkdir newdir
find . -type f -name '*.gz' -print0 |\
xargs -0 -r stat --printf="%s:%N" |\
sort -rn |\
head -n 2 |\
cut -d: -f 2 |\
xargs cp -T newdir
警告!未经测试的代码(我正在打电话)。将最后一行替换为
xargs echo cp -T newdir
直到它发挥作用。