특정 유형의 x 파일이 포함된 폴더를 찾고 OSX에서 해당 경로를 출력하려면 어떻게 해야 합니까?

특정 유형의 x 파일이 포함된 폴더를 찾고 OSX에서 해당 경로를 출력하려면 어떻게 해야 합니까?

하나의 파일만 포함된 폴더를 찾고 해당 파일이 오디오 파일의 경로를 출력하는 오디오 파일인 경우 OSX용 스크립트가 있습니다.

find "$1" -type d -exec sh -c '[[ $(find "$0" -mindepth 1 | wc -l) -eq 1 ]] 
&& [[ $(find "$0" -mindepth 1 -type d | wc -l) -eq 0 ]]  
&& find "$0"' {} \; |egrep ".mp4|.mp3|.ogg|.flac|.wma|.m4a"

즉, 다음과 같이 사용하세요

./findodd.sh /Users/paul/Music

하지만 두 가지 개선이 필요합니다.

  1. 2개 파일, 3개 파일 등이 포함된 폴더의 파일을 나열하도록 무엇을 변경할 수 있습니까? 매개변수로 전달할 수 있다면 더 좋을 것입니다.

  2. 현재는 하나의 파일만 포함된 폴더를 찾고 해당 파일은 오디오 파일이어야 합니다. 하지만 제가 정말로 원하는 것은 하나의 오디오 파일만 포함된 폴더를 찾는 것입니다. 즉, 폴더에 세 개의 파일이 포함되어 있지만 하나만 오디오 파일인 경우 해당 오디오 파일이 나열되기를 원합니다.

고마워요 폴

답변1

$ find
.
./folder3
./folder3/quux.txt
./folder1
./folder1/test.mp3
./folder1/test.txt
./folder1/test.wma
./folder2
./folder2/bar.txt
./folder2/foo.txt
./folder2/test.ogg

예시 실행:

$ ./findaudio.sh /tmp/findaudio 1
/tmp/findaudio/folder2/test.ogg

$ ./findaudio.sh /tmp/findaudio 2
/tmp/findaudio/folder1/test.mp3
/tmp/findaudio/folder1/test.wma

# The first parameter defaults to the current directory and
# the second parameter defaults to 1 so this works as well:
$ ./findaudio.sh
./folder2/test.ogg

코드는 다음과 같습니다.

#!/bin/bash

shopt -s nullglob

find "${1:-.}" -type d | while read dir; do
        files=( "${dir}"/*.{mp4,mp3,ogg,flac,wma,m4a} )
        IFS=$'\n'
        (( ${#files[@]} == ${2:-1} )) && echo "${files[*]}"
done

지정된 디렉토리의 모든 하위 디렉토리를 반복하고 globbing을 사용하여 현재 하위 디렉토리의 모든 오디오 파일 이름을 배열로 읽습니다 files. 배열의 크기가 원하는 값과 일치하면 줄 바꿈으로 구분된 파일 이름을 인쇄합니다.

편집: 이것은 문제의 파일 이름이 아니라 폴더를 인쇄하고 싶다는 가정을 기반으로 한 이전 접근 방식입니다. 나중에 참고할 수 있도록 여기에 남겨 두겠습니다.

$ find . \( -name '*.ogg' -o -name '*.wma' -o -name '*.mp3' \) -printf "%h\n" | uniq -u
./folder2

이것이 수행하는 작업은 나열된 오디오 확장자를 가진 모든 파일을 찾고 전체 경로 대신 해당 디렉토리 구성 요소만 인쇄하는 것입니다. 그러면 모든 오디오 파일의 상위 폴더 목록이 제공됩니다. uniq즉, 정확히 하나의 오디오 파일이 포함된 폴더만 인쇄하는 결과를 제공해야 하는 고유하지 않은 줄을 건너뜁니다 .

이는 이론적으로 이전 시도보다 상당히 빨라야 합니다.

중복된 줄 수를 세고 요청한 수와 일치하는 폴더만 인쇄하여 이를 개선하여 첫 번째 요점을 만족시킬 수 있습니다. 순진한 해결책은 다음과 같습니다.

$ find . \( -name '*.ogg' -o -name '*.wma' -o -name '*.mp3' \) -printf "%h\n" | uniq -c | awk -v count=1 '$1==count'
1 ./folder2

$ find . \( -name '*.ogg' -o -name '*.wma' -o -name '*.mp3' \) -printf "%h\n" | uniq -c | awk -v count=2 '$1==count'
2 ./folder1

uniq하지만 파이프의 오른쪽 부분과 오른쪽 부분을 한 줄로 융합하는 것이 더 나을 수도 있습니다 awk.

답변2

두 번째 시도

좋습니다. 실제로 내 Music 폴더에서 이 작업을 직접 시도한 결과 다음 두 가지 요청에 대한 솔루션이 나왔습니다.

COMMAND='[[ $(find "$0" -maxdepth 2 |egrep "\.mp4|\.mp3|\.ogg|\.flac|\.wma|\.m4a"| wc -l) == '$2' ]] && echo "$0"'
find $1 -type d -exec sh -c "$COMMAND" {} \;

따라서 스크립트에 몇 가지 문제가 있었습니다.

  1. mindepth대신 사용하고 계셨습니다 maxdepth.
  2. egrep의 마침표(.)는 모든 문자와 일치합니다. 따라서 .wma'Snowman.txt'와 일치했을 것입니다.
  3. 디렉토리만 쉘 명령에 전달되므로 'd' 유형에 대해 두 번째 테스트를 수행할 필요가 없습니다.

내 스크립트에 대한 참고 사항:

  1. 사용법은 다음과 같습니다:findodd.sh <top_folder> <no_of_files>
  2. 인용문은 매우 중요합니다. 의 정의는 COMMAND실제로 의 양쪽에 2개의 문자열 리터럴입니다 $2. 정말 중요해요.
  3. 파일 자체가 아닌 파일이 포함된 폴더만 나열합니다. 후자를 수행하려면 를 echo "$0"다른 으로 바꿔야 합니다 find.

이제 저는 Arch Linux 시스템에서 테스트를 해왔고 제 쉘은 'bash'이므로 모든 쉘이 동일하게 생성되지 않기 때문에 이것이 OSX에서 작동할지 모르겠습니다. :-)


초기 첫 번째 시도:

흠. OSX가 Unix/Linux와 얼마나 유사한지는 모르겠지만, 이에 대해 한 번 살펴보겠습니다.

두 가지 질문에 대한 답은 'sh -c' 명령의 첫 번째 테스트에 있다고 생각합니다. 그 내용은 다음과 같습니다.

$(find "$0" -mindepth 1 | wc -l) -eq 1

파일 수에 대한 두 번째 매개변수를 스크립트에 전달하려면 '1'을 $2로 변경하면 됩니다. 따라서 테스트는 다음과 같습니다.

$(find "$0" -mindepth 1 | wc -l) -eq $2

앞뒤에 따옴표를 넣지 마십시오. $2그렇지 않으면 스크립트가 아닌 'sh -c' 명령에 전달된 두 번째 매개변수로 해석됩니다.

그러면 명령줄은 다음과 같습니다.

./findodd.sh /Users/paul/Music 2

egrep두 번째 요구 사항을 충족하려면 첫 번째 테스트에 명령을 넣어야 합니다 .

$(find "$0" -mindepth 1 |egrep ".mp4|.mp3|.ogg|.flac|.wma|.m4a"| wc -l) -eq $2

하지만 인용문을 봐야 할 수도 있습니다.

어쨌든 한번 시도해 보고 알려주세요.

답변3

다음과 같이 Python에서 이를 구현할 수 있습니다.

#!/usr/bin/env python

import fnmatch
import os
import sys

if len(sys.argv) != 3 or \
        not sys.argv[1].isdigit() or \
        not os.path.exists(sys.argv[2]):
    print "Usage: %s [number of files] [search root]" % sys.argv[0]
    sys.exit(1)

num_files = int(sys.argv[1])
search_root = sys.argv[2]

# this must be a tuple to work with endswith()
audio_extensions = (
    'mp4',
    'mp3',
    'ogg',
    'flac',
    'wma',
    'm4a',
)

for dirpath, dirnames, filenames in os.walk(search_root):
    audio_files = [f for f in filenames if f.endswith(audio_extensions)]
    if len(audio_files) == num_files:
        print "\n".join([os.path.join(dirpath, f) for f in audio_files])

chmod +x findodd.py그런 다음 현재 스크립트를 실행하는 것과 동일한 방식으로 실행할 수 있다면 다음과 같습니다 .

./findodd.py 1 /Users/paul/Music

관련 정보