모든 디렉토리에서 10MB보다 작은 mp4 파일을 반복적으로 검색합니다.

모든 디렉토리에서 10MB보다 작은 mp4 파일을 반복적으로 검색합니다.

크기가 10MB 미만인 mp4 파일이 포함된 모든 디렉터리를 반복적으로 찾으려고 합니다.

요구 사항은,

  1. 디렉토리에는 mp4 파일이 하나만 있을 수 있습니다.
  2. mp4 파일은 10MB를 초과할 수 없습니다.

내가 사용하는 명령은

% find . -type f -name "*.mp4" -size -10M | cut -d/ -f2 | sort | uniq -c | grep "^      1"

무슨 일이 일어나고 있는지 잘 모르겠지만 이 명령은 정확한 결과를 반환하지 않습니다.

추가 조사 결과 다음 명령이 작동하는 것으로 나타났습니다.

find . -type 'f' -name "*.mp4" -printf '%h\n' | sort | uniq -c | grep -E "\s+1\s"| cut -c 9-

그런데 믹스에 추가해보니 -size -10000000c해당 파일에 10MB 미만의 mp4 파일이 1개 있고, 10MB가 넘는 다른 mp4 파일도 있는 것으로 나타났습니다. 내 말은 내가 언급한 명령은 크기가 10MB보다 큰 mp4 파일을 고려하지 않는다는 것입니다. 이 질문은 두 단계로 나눌 수 있다고 생각합니다.

  1. mp4 파일이 포함된 모든 디렉터리를 찾습니다. 이는 위의 명령으로 수행됩니다.

  2. 파일이 10MB보다 작은지 확인하세요.

다음 명령을 사용하여 디렉터리에 있는 단일 mp4 파일의 파일 크기를 얻을 수 있습니다.

find . -type 'f' -name "*.mp4" -printf '%h\n' | sort | uniq -c | grep -E "\s+1\s" | cut -c 9-| xargs -I {} -n 1 /usr/bin/du -a "{}" | grep -v ".mp4$"

답변1

find적어도 GNU의 경우 -size -10M이는 다음 메가바이트로 반올림된 크기가 10보다 작은(즉, 9 이하) 파일의 경우에 해당됩니다.

크기가 9 x 1024 x 1024 + 1 = 9437185바이트인 파일은 10MiB로 반올림되어 10 미만이 아니므로 선택되지 않습니다.

10MB(1MB는 1,000,000바이트, 1메비바이트 == 1,048,576바이트와 혼동하지 마세요)보다 엄격하게 작아서 크기가 0~9,999,999인 파일의 경우 다음을 사용하세요.

find . -size -10000000c

10MiB보다 엄격하게 작은 파일의 경우 크기 범위는 0에서 10485759입니다.

find . -size -10485760c

이제 GNU 시스템에서 이러한 파일 중 하나만 포함하는 디렉토리를 얻으려면 다음을 수행할 수 있습니다.

LC_ALL=C find . -name '*.mp4'  -type f -size -10000000c -printf '%h\0' |
  LC_ALL=C sort -z |
  LC_ALL=C uniq -zu |
  tr '\0' '\n'

어디

  • findh이러한 파일의 ead(디렉토리 이름)를 NUL로 구분하여 인쇄합니다 ( 현재 로케일에서 유효한 텍스트가 아니더라도 LC_ALL=C다른 방식으로 끝나는 모든 파일 이름은 보고됩니다 )..mp4
  • sort이를 정렬합니다 uniq( LC_ALL=C파일 이름이 로케일에서 유효한 텍스트가 아닌 문제 및 문자가 완전히 정의된 순서가 아닌 문제를 피하기 위해 다시 한 번).
  • uniq -zu고유한 항목만 보고됩니다.

NUL은 파일 경로에 나타날 수 없는 유일한 문자이기 때문에 파일 목록은 NUL로 구분되어 전달됩니다. 우리는 이러한 NUL을 사람이 사용할 수 있도록 개행 문자로 변환하게 됩니다 tr.

를 사용하면 zsh다음 작업도 수행할 수 있습니다.

print -rC1 -- **/*(NFe['()(( $# == 1 )) $REPLY/*.mp4(N.L-10000000Y2)'])

어디:

  • print -rC1 -- print그것은 olumn r에 대한 논쟁입니다.1 C
  • **/하위 디렉터리 수에는 제한이 없습니다.
  • *(NF...)임의의 파일 이름(숨겨진 파일 제외)이지만 , N, F... glob 한정자로 e추가로 한정됩니다 .
  • N: nullglob불일치 시 오류를 반환하는 대신 null로 확장되도록 이 glob을 활성화합니다.
  • F: 모든 디렉토리( F및를 제외하고 하나 이상의 항목이 있는 디렉토리)를 선택합니다....
  • e[code]:성공적인 파일을 선택합니다 code.
  • () {body} arguments여러 매개변수가 있는 익명 함수입니다.
  • 반환 된 산술 평가 {body}입니다 .(( $# == 1 ))진짜이 익명 함수의 매개변수 개수가 1인 경우.
  • $REPLY내부에는 code고려 중인 파일(여기서는 디렉터리)의 경로가 있습니다.
  • *.mp4(qualifiers): (숨겨지지 않은) mp4파일이 추가로 한정됩니다.
  • .: 일반 파일만(예: find's' -type f)
  • L-10000000: 파일 크기는 10MB보다 엄격하게 작습니다.
  • Y2: 2개의 파일을 찾은 후 최적화를 중지합니다.

.(현재 작업 디렉터리 자체)은 고려되지 않습니다 . 이를 고려하고 싶다면 **/*로 바꾸십시오 {.,**/*}.


이제 명확하게 설명했듯이 mp4 파일이 하나만 포함된 디렉터리를 찾고 해당 파일이 일반 파일(디렉토리, 심볼릭 링크가 아님...)이고 크기가 10MB 미만인 경우(예를 들어 를 포함하는 디렉터리 제외): 5MB 및 15MB mp4 파일(크기에 관계없이 총 여러 개의 mp4가 있으므로 10MB보다 작은 mp4 파일이 하나만 있음에도 불구하고) 여전히 다음과 같습니다 zsh.

print -rC1 -- **/*(NFe['
    () {
      (( $# == 1 )) && ()(($#)) $1(N.L-10000000)
    } $REPLY/*.mp4(NY2)
  '])

GNU find및 GNU awk(또는 NUL로 구분된 레코드를 처리할 수 있는 awk)의 경우 다음과 같습니다.

LC_ALL=C find . -name '*.mp4' -printf '%h\0%s\0%y\0' |
  awk -v RS='\0' '
   {
     getline size; getline type
     total[$0]++
     if (size < 10e6 && type == "f") found[$0]++
   }
   END {for (dir in found) if (total[dir] == 1) print dir}'

답변2

find훌륭해요. 저는 이보다 훨씬 더 복잡한 작업에 항상 이 프로그램을 사용합니다... 하지만 때로는 모든 find옵션을 파악하고 원하는 작업을 수행하도록 한 다음, sort등과 같은 다른 프로그램을 사용하는 것이 좋을 때도 있습니다. PITA의 경우 디렉토리를 재귀적으로 검색하기 위한 괜찮은 라이브러리가 있는 언어로 원하는 작업을 수행하는 사용자 정의 도구를 직접 작성하고 이를 수행하려면 쉘 명령줄 편집기 대신 괜찮은 편집기를 사용하는 것이 더 쉬운 것 같습니다.grepuniq

따라서 다음과 같은 또 다른 작은 변형을 작성하게 됩니다. wanted서브루틴을 변경하면 find함수가 발견하는 내용이 변경됩니다. 그러면 파일 이름이 다음으로 끝나는 크기 <= 10MiB의 일반 파일이 하나 이상 포함된 디렉터리 목록이 인쇄됩니다 .mp4.

$ cat find-mp4-1.pl 
#!/usr/bin/perl

use strict;
use File::Find;

my %found;

sub wanted {
  -f $_ && -s $_ <= 10485760 && /\.mp4\Z/s &&
    $found{$File::Find::dir . "/"}++;
};

# Search all directories listed on command line.
# Default to current directory
find(\&wanted, @ARGV ? @ARGV : '.');

print join("\n", sort keys %found), "\n" if %found;

나는 이와 같은 작은 스크립트를 너무 많이 작성해서 File::Find셀 수 없을 만큼 많이 작성했습니다.

실행 예시:

$ mkdir videos
$ touch video1.mp4 videos/video2.mp4
$ ./find-mp4-1.pl 
./
./videos/

그러면 때로는 NUL로 구분된 출력을 사용하는 것이 유용하므로 -0옵션이 필요하다는 것을 깨닫게 됩니다. 이 작업이 완료되면 명령줄에서 원하는 크기를 지정할 수 있으면 좋을 것이라고 생각했습니다. 파일 이름 패턴 일치에도 동일하게 적용되며 대소문자를 구분하지 않는 검색 옵션이 있으면 좋을 것입니다. 따라서 " 사람이 읽을 수 있는" 크기, I 정규식을 미리 컴파일하고 파일 이름의 기본 이름 부분만 일치시키면(조금 조기 최적화를 좋아하지 않는 사람) 조금 더 빠르게 만들 수 있습니다. 그리고... 정신을 차리고 다음을 수행하십시오.

$ cat find-mp4-2.pl
#!/usr/bin/perl

use strict;
use File::Find;
use Number::Bytes::Human qw(parse_bytes);
use Getopt::Std;

my %found;

my %opts;
$Getopt::Std::STANDARD_HELP_VERSION=1;
our $VERSION='0.2';
getopts('0:s:r:i',\%opts) ||
  die "Usage: $0 [-0] [-s size] [-r regex] [-i] [directory...]\n";

my $sep   = $opts{0} ? "\0" : "\n";
my $size  = $opts{s} // '10MiB';
my $regex = $opts{r} // '\.mp4\Z';

$size  = parse_bytes($size);

# pre-compile the regex: case insensitive or case sensitive?
$regex = $opts{i} ? qr/$regex/si : qr/$regex/s;

sub wanted {
  -f $_ && -s $_ <= $size && $File::Find::name =~ /$regex/ &&
    $found{$File::Find::dir . "/"}++;
};

find(\&wanted, @ARGV ? @ARGV : '.');

print join($sep, sort keys %found), $sep if %found;

노트:파일::찾기그리고GetSelect::표준핵심 Perl 모듈이며 Perl에 포함되어 있습니다. 수량::바이트::인간아니요, 별도로 설치해야 합니다(Debian 및 그 파생 제품: sudo apt-get install libnumber-bytes-human-perl. 다른 배포판에서도 패키지할 수 있습니다. 그렇지 않으면 으로 설치 cpan).

또는 원시 원시인처럼 및 use Number::Bytes::Human qw(parse_bytes);행을 제거하고 파일 크기를 바이트 단위로 지정하십시오.$size = parse_bytes($size);

그리고 나서 당신은 "흠... 어쩌면 내가 사용해야 할지도 모르겠다"고 생각합니다Getopt::긴옵션을 Getopt::Std처리할 수 있는 것보다 디렉터리의 일치 항목 수를 출력하는 옵션을 갖는 것이 유용하고 필요할 수 있습니다.--long-c문서그리고...". 어쩌면 그렇게 하기 위해 수정을 시작하다가 "안돼! 이것은미친. 도구를 만드는 것은 재미있지만 그것만으로도 충분합니다. "

미친 사람이 어떤 이름이나 이름도 언급하지 않고 할 수 있는 일에 대한 가상의 예처럼 말입니다. 나는 언제든지 멈출 수 있다. 후원자의 전화번호는 어디에 있나요? 내 생각엔 그 사람들에게 전화해야 할 것 같아.


그런데 다음을 포함하는 디렉토리만 인쇄합니다.정확히일치하는 비디오의 경우 print join ...행을 다음과 같이 변경할 수 있습니다.

  foreach (sort keys %found) {
    print "$d\n" if $found{$_} == 1
  };

(또는 print "$d$sep" ...두 번째 버전)

이는 여러 개의 .mp4 파일이 포함된 디렉터리를 인쇄하며 그 중 하나만 <= 10MB입니다. 이를 제외하려면 wanted해시에 입력되지 않도록 %found(또는 함수가 완료되기 전에 해시에서 제거되도록 find()) 서브루틴을 수정해야 합니다 . 다음과 같이 여러 .mp4 파일이 발견된 디렉터리를 추적하기 위해 다른 해시를 사용할 수도 있습니다.

sub wanted {
  next unless -f $_ && $File::Find::name =~ /\.mp4\Z/s;

  my $d = $File::Find::dir . '/';
  $seen{$d}++;

  if ($seen{$d} > 1) {
    delete $found{$d};
  } else {
    $found{$d} = 1 if -s $_ <= 10485760;
  }
};

그리고 my %found;그 줄을 다음과 같이 바꾸세요.my (%found, %seen);

관련 정보