여러 조건(디렉터리의 특정 파일 및 해당 디렉토리 내의 특정 하위 디렉터리)을 사용하여 find -exec {}를 최적화합니다.

여러 조건(디렉터리의 특정 파일 및 해당 디렉토리 내의 특정 하위 디렉터리)을 사용하여 find -exec {}를 최적화합니다.

내 질문은 내 NAS의 음악 인코딩 및 Linux 명령 최적화와 관련이 있습니다 find.

나는 완벽하게 작동하는 스크립트를 작성했지만 그것이 최선의 접근 방식은 아니라고 확신합니다.

결론적으로:

1/ 스크립트는 인코딩할 flac가 포함된 디렉터리를 확인합니다.

  • .flac특정 파일을 포함하는 모든 디렉토리
  • mp3/또는 이름의 하위 디렉터리를 포함하지 않는 디렉터리Mp3/

특정 부분에 대해 나는 다음과 같이 했습니다.

FILE="./DirContaininfFlacToConvertToMp3.txt"
find . -type f -iname '*.flac' -printf '%h\n' | sort -u > fic1
find . -iname 'mp3' -type d | sort | sed 's/\/Mp3//' | sed 's/\/mp3//' > fic2
comm -3 fic1 fic2 > $FILE
  • $FILE은 이 두 가지 기준과 일치하는 모든 디렉터리를 채웁니다.
  • fic1파일에는 flac 파일이 포함된 모든 디렉터리가 포함되어 있습니다.
  • fic2mp3/파일에는 mp3 하위 디렉터리가 포함된 모든 디렉터리가 포함되어 있습니다(sed는 comm 명령이 작동하도록 경로 끝에서 또는 를 제거하는 데 사용됩니다 ).Mp3/
  • comm -3내 결과를 나에게 제공$FILE

잘 작동하지만 최선의 방법은 아니라고 확신합니다. 조회 매개변수를 사용하거나 이를 셸에 전달하여 최적화하면 됩니다.

2/ 스크립트는 flac 파일을 인코딩하여 Mp3/ 하위 디렉터리로 이동합니다.

file( $FILE)이 다음 기준과 일치하는 디렉터리 결과를 제공하면 다음을 수행합니다.

  • mp3정의된 디렉터리에 파일을 인코딩합니다.
  • Mp3(원래 구조 유지) 라는 하위 디렉토리로 옮겼습니다.

이 부분에서는 두 가지 루프로 수행했습니다.

#1st loop to encode
IFS=$'\n'
for next in `cat $FILE`
do
  find $next -type f  -name "*.flac" -exec ffmpeg -i {} -qscale:a 2 -map_metadata 0 -id3v2_version 3 {}.mp3 \;
done

#2nd loop for moving to subdir
for next in `cat $FILE`
do
  find $next -type f -name '*.flac.mp3' -execdir mkdir -p Mp3 \; -execdir mv {} Mp3/ \;
done

또한 2개의 루프 반복을 피할 수 있다고 확신합니다.

그러나 여기에서 어떤 목적으로든 완전한 스크립트를 찾을 수 있습니다(코딩이 별로 좋지 않다는 것을 알고 있습니다... :-(

전체 스크립트

#!/bin/bash
# Convert .flac en .mp3 file for Synology with ffmpeg
# usage : 1st construct list of directory to convert : run:  ./script.sh V
#         2nd verify and to convert run : nohup ./script C & 

#result of list of directories to encode
FILE="./ToConvertToMp3.txt"

# parameter validation
if [ "$#" -ne  "1" ]
  then
     echo "1 parameter required : ./script.sh (V)erify (C)onvert "
 exit 1;
fi


# generate list of directory for encoding
if [ "$1" ==  "V" ]
  then
    echo "-------- VERIFY AND CONSTRUCT LIST -------"
    #1 find dir that contains .flac file
    find . -type f -iname '*.flac' -printf '%h\n' | sort -u > fic1

    # for those directory search if there is some *mp3* subdir
    IFS=$'\n'
    for dirflac in `cat fic1`
    do
      find $dirflac -iname '*mp3*' -type d -exec dirname {} \; >> fic2
    done

    # sort and unicity
    cat fic2 | sort -u > fic3

    # final construc of the list of directory to encode
    comm -3 fic1 fic2 > $FILE
    rm -f fic1 fic2 fic3

    echo "-----DIRECTORY TO CONVERT-------"
    cat $FILE
    echo "-------------------------------------"
    exit 0
fi

# Converting .flav files from directories listed in $FILE
if [ "$1" ==  "C" ]
  then
    echo "-------- CONVERTING FLAC -------"

    if [ -e $FILE ]; then
      echo "$FILE exist : OK"
    else
      echo "$FILE does not exist Please (V)erification first"
    exit 3
    fi

  if [ -s "$FILE" ]; then
    echo "$FILE contains directories : OK"
    cat $FILE
  else
    echo "$FILE is empty , nothing to do"
    exit 2
  fi

  echo "-------- CONVERTING -------"
  IFS=$'\n'
  for next in `cat $FILE`
  do
    find $next -type f  -name "*.flac" -exec ffmpeg -i {} -qscale:a 2 -map_metadata 0 -id3v2_version 3 {}.mp3 \;
    album="$(basename $directory)-Mp3";
    echo "  Processing $directory : creating subdirectory : $album, moving files in progress"
    find $directory -type f -name '*.flac.mp3' -execdir mkdir -p "$album" \; -execdir mv {} "$album/" \;

  done
  echo "-------- END OF CONVERSION -------"

  # renaming $FILE with timestamp
  ficdate=$(date +%Y%M%d-%Hh%m);
  mv $FILE $FILE-$ficdate.done;

  exit 0
fi

echo "WARNING : 1 parameter : usage : ./script.sh (V)erification (C)onversion"

답변1

다음을 수행할 수 있습니다.

find . -type f -name '*.flac' -execdir sh -c '
  if [ ! -d mp3 ] && [ ! -d Mp3 ]; then
    for file do
      ffmpeg -i "$file" -qscale:a 2 -map_metadata 0 -id3v2_version 3 "${file%.*}.mp3"
    done
  fi' sh {} +

아이디어는 -execdir cmd {} +(일부 GNU 버전의 경우 find) with 가 주어진 디렉토리에서 일치하는 모든 파일에 대해 실행된다는 것입니다 find.cmd

나는 말했다GNU Find의 일부 버전예전에는 그렇게 작동했지만 나중에 일부 버전에서 손상되었고 (각 파일이 사용한 것처럼 호출을 find받음 ) 이후 버전에서 다시 수정되었습니다.cmd-execdir cmd {} \;

가지고 있는지 확인할 수 있습니다.옳은버전:

find . -execdir echo {} +

올바른 버전의 경우 디렉터리당 한 줄을 가져와야 하고, 덜 정확한 버전의 경우 파일당 한 줄을 가져와야 합니다.

올바른 버전이 있고 디렉터리당 수천 개의 flac 파일이 없는 경우 두 가지를 동시에 수행할 수 있습니다.

find . -type f -name '*.flac' -execdir sh -c '
  if [ ! -d mp3 ] && [ ! -d Mp3 ]; then
    mkdir Mp3 || exit
    for file do
      ffmpeg -i "$file" -qscale:a 2 -map_metadata 0 -id3v2_version 3 "Mp3/${file%.*}.mp3"
    done
  fi' sh {} +

관련 정보