For循环查找最大大小的文件并将它们复制到另一个目录

For循环查找最大大小的文件并将它们复制到另一个目录

我试图创建一个循环来按大小对每个目录中的文件进行排序,然后将最大的两个复制到另一个位置,保持目录格式(如下)。

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
  1. find查找给定的文件"$dir"- 您应该在此处使用引号。它还适用du于所有文件以获取其大小。
  2. sort按大小对结果进行排序。
  3. head限制为前 2 个。
  4. sed删除文件名之前的大小值。
  5. xargs使用管道中的参数构建实际命令。

NUL 分隔符通常必须在所有命令中指示,因此 、和;z中有标志。在和;它们是由的开关产生的。sortheadsed0duxargs-print0find

(我不知道你为什么-T在 中使用该标志cp。在我的示例中它不存在,而是-v提供反馈。)

答案3

您的代码有两个问题:

  1. 永远不要尝试解析 的输出lsstat而是使用;
  2. 当文件“很多”或文件名包含“有趣”字符(“ /sample 1/”)时,请使用findxargs。请参阅man findman 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

直到它发挥作用。

好奇的可以看看https://mywiki.wooledge.org/ParsingLs

相关内容