使用多个条件优化 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 将填充所有符合这两个条件的目录。
  • fic1file 包含包含 flac 文件的所有目录。
  • fic2文件包含所有包含 mp3 子目录的目录(sed 用于消除路径末尾的mp3/或以使 comm 命令起作用)Mp3/
  • comm -3向我提供我的结果$FILE

它工作正常,但我很确定这不是最好的方法,只需使用查找参数或将其传递给 shell 即可对其进行优化。

2/ 脚本对 flac 文件进行编码并移动到 Mp3/ 子目录

一旦文件 ( $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 {} +

这个想法是, with -execdir cmd {} +, (对于某些版本的 GNU find),将为给定目录中的所有匹配文件find运行。cmd

我说某些版本的 GNU 查找因为它曾经是这样工作的,但后来在某些版本中被破坏了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 {} +

相关内容