Adakah perangkat lunak pendeteksi ketukan untuk Linux? [Tutup]

29

Amarok 2 dapat mencari melalui koleksi musik menggunakan bidang 'bpm' tag ID3v2. Itu akan sangat bagus untuk mengecek ulang seluruh koleksi musik sehingga saya dapat menemukan 'mood' dari lagu yang saya sukai.

Namun saya belum menemukan perangkat lunak pendeteksi ketukan yang bisa membantu saya. Apakah Anda pernah menggunakannya? CLI, lebih disukai. Saya juga tertarik jika ada sesuatu yang sama untuk menandai FLAC dengan bidang 'bpm' yang sama.

Terima kasih! :)

PS Saya sadar ada fitur moodbar yang bagus, namun tidak berguna untuk mencari.

kolypto
sumber
3
Pernahkah Anda melihat halaman ini? mmartins.com/mmartins/bpmdetection/bpmdetection.asp Tampaknya persis apa yang Anda cari.
DaveParillo
@DaveParillo bahwa tautan "mood of a track" adalah tautan ke cakram keras Anda, dan dengan demikian tidak berguna bagi siapa pun kecuali Anda
Justin Smith
@Justin Smith, maksudnya file dalam dokumen BpmDj :) Inilah versi online: bpmdj.yellowcouch.org/clustering.html
kolypto
@ Justin - maaf - jari pemicu gugup, saya kira.
DaveParillo

Jawaban:

17

Di situs tersebut DaveParillo menyarankan saya telah menemukan proyek BpmDj . Ini memiliki bpmcountexecutable yang menghitung bpm sangat bagus: ini menangani mp3 dan juga flac:

161.135 Metallica/2008 - Death Magnetic/01-That Was Just Your Life.flac
63.5645 Doom3.mp3

Satu-satunya hal yang tersisa adalah retag koleksi. Saya akan memperbarui jawaban ini setiap kali saya berhasil. Terima kasih! :)


Langkah 1

Jalankan bpmcountmelawan seluruh koleksi dan simpan hasilnya ke dalam file teks. Masalahnya adalah bpmcountcrash dari waktu ke waktu dan mencoba memakan memori hingga 2GB ketika memproses beberapa file sehingga kita harus memberinya makan dengan nama file satu per satu. Seperti ini:

musicdir='/home/ootync/music'
find "$musicdir" -iregex ".*\.\(mp3\|ogg\|flac\|ape\)" -exec bpmcount {} \; \
    | fgrep "$musicdir" > "$musicdir/BPMs.txt"

Langkah 2

Kita akan membutuhkan beberapa paket tambahan: apt-get install vorbis-tools flac python-mutagen. Sekarang lihat bagaimana tag 'bpm' dapat ditambahkan:

mid3v2 --TBPM 100 doom3.mp3
vorbiscomment -a -t "BPM=100" mother.ogg
metaflac --set-tag="BPM=100" metallica.flac

Sayangnya, saya tidak punya lagu * .ape

Sekarang kami memiliki BPM dan seluruh koleksi harus diperiksa ulang. Ini skripnya:

cat "$musicdir/BPMs.txt" | while read bpm file ; do
    bpm=`printf "%.0f" "$bpm"` ;
    case "$file" in 
        *.mp3) mid3v2 --TBPM "$bpm" "$file" > /dev/null ;; 
        *.ogg) vorbiscomment -a -t "BPM=$bpm" "$file" ;; 
        *.flac) metaflac --set-tag="BPM=$bpm" "$file" ;; 
        esac
    done

Langkah 2.1 Tinjau Kembali Ini adalah skrip yang akan menambahkan tag BPM ke koleksi Anda.

Ini menjalankan satu proses per CPU Core untuk membuat proses lebih cepat. Selain itu, tidak menggunakan file sementara dan mampu mendeteksi apakah file sudah ditandai.

Selain itu, saya menemukan bahwa FLAC terkadang memiliki ID3 dan VorbisComment di dalamnya. Script ini memperbarui keduanya.

#!/bin/bash

function display_help() {
    cat <<-HELP
            Recursive BPM-writer for multicore CPUs.
            It analyzes BPMs of every media file and writes a correct tag there.
            Usage: $(basename "$0") path [...]
            HELP
    exit 0
    }

[ $# -lt 1 ] && display_help

#=== Requirements
requires="bpmcount mid3v2 vorbiscomment metaflac"
which $requires > /dev/null || { echo "E: These binaries are required: $requires" >&2 ; exit 1; }

#=== Functions

function bpm_read(){
    local file="$1"
    local ext="${file##*.}"
    declare -l ext
    # Detect
    { case "$ext" in
        'mp3')  mid3v2 -l "$file" ;;
        'ogg')  vorbiscomment -l "$file" ;;
        'flac') metaflac --export-tags-to=- "$file" ;;
        esac ; } | fgrep 'BPM=' | cut -d'=' -f2
    }
function bpm_write(){
    local file="$1"
    local bpm="${2%%.*}"
    local ext="${file##*.}"
    declare -l ext
    echo "BPM=$bpm @$file"
    # Write
    case "$ext" in
        'mp3')  mid3v2 --TBPM "$bpm" "$file" ;;
        'ogg')  vorbiscomment -a -t "BPM=$bpm" "$file" ;;
        'flac') metaflac --set-tag="BPM=$bpm" "$file"
                mid3v2 --TBPM "$bpm" "$file" # Need to store to ID3 as well :(
                ;;
        esac
    }

#=== Process
function oneThread(){
    local file="$1"
    #=== Check whether there's an existing BPM
        local bpm=$(bpm_read "$file")
        [ "$bpm" != '' ] && return 0 # there's a nonempty BPM tag
    #=== Detect a new BPM
    # Detect a new bpm
    local bpm=$(bpmcount "$file" | grep '^[0-9]' | cut -f1)
    [ "$bpm" == '' ] && { echo "W: Invalid BPM '$bpm' detected @ $file" >&2 ; return 0 ; } # problems
    # Write it
    bpm_write "$file" "${bpm%%.*}" >/dev/null
    }

NUMCPU="$(grep ^processor /proc/cpuinfo | wc -l)"
find $@ -type f -regextype posix-awk -iregex '.*\.(mp3|ogg|flac)' \
    | while read file ; do
        [ `jobs -p | wc -l` -ge $NUMCPU ] && wait
        echo "$file"
        oneThread "$file" &
        done

Nikmati! :)

kolypto
sumber
Luar biasa! Saya belum sempat mencoba ini tadi malam. Sejauh penandaan baris perintah, coba mid3v2: linux.die.net/man/1/mid3v2 , dapat digunakan setidaknya sampai Ex Falso mendukung pengeditan baris perintah. Id3v2 tad id adalahTBPM
DaveParillo
1
Terima kasih, saya akan mencoba dalam beberapa hari dan memposting hasilnya :) Saya ingin tahu apakah FLAC mendukung hal seperti itu: Saya harus memeriksa ini.
kolypto
1
Kerja bagus di langkah # 2. Seandainya aku bisa menang dua kali!
DaveParillo
1
Terima kasih :) Sayangnya, Amarok saya tidak melihat tag baru dalam FLAC yang paling saya sukai :)) bug dikirimkan.
kolypto
Bagaimana Anda menginstalnya? rpm yang mereka berikan sepertinya tidak berfungsi di komputer saya dan saya kesulitan dengan kompilasi.
pedrosaurio
6

Saya menggunakan skrip asli kolypto menggunakan bpmcountdan menulis ulang untuk bpm-tag(utilitas bpm-tools) yang saya lebih beruntung menginstalnya. Saya juga membuat beberapa perbaikan sendiri.

Anda dapat menemukannya di GitHub https://github.com/meridius/bpmwrap

meridius
sumber
Ini memerlukan beberapa modifikasi untuk bekerja pada Mac, yang telah saya sertakan dalam jawaban saya sendiri di bawah (karena terlalu lama untuk komentar)
Adrian
2

Saya tidak tahu alat yang melakukan persis apa yang Anda cari, tetapi saya telah bermain-main dengan MusicIP .

Menggunakan versi linux / java - butuh waktu lama untuk sepenuhnya menganalisis perpustakaan musik, tetapi itu benar-benar berfungsi. Anda dapat menemukan lagu yang mirip dengan lagu lain. Anda dapat mengeklik kanan daftar putar yang dibuat dan memilih opsi untuk memilih lebih banyak atau lebih sedikit lagu seperti yang dipilih. Anda juga dapat memilih untuk menghilangkan genre tertentu. Agak keren, tapi setelah faktor wow hilang, saya berhenti menggunakannya.

Versi gratis mengekspor daftar putar hingga 75 lagu dalam (setidaknya) format m3u.

Saat ini tidak didukung, tetapi saya pikir mereka telah mencoba untuk menjadikannya komersial sebagai Predexis .

DaveParillo
sumber
1

Meskipun bukan hanya alat seperti yang Anda katakan sedang Anda cari, Banshee media player dapat mendeteksi bpm.

Saya menggunakan Banshee untuk semua pemutaran musik, pengorganisasian, dan sinkronisasi ke pemutar portabel saya. Saya tidak berafiliasi, tapi saya suka program yang terbaik dari semua yang saya coba. Itu juga dapat menghasilkan "daftar putar cerdas" berdasarkan semua jenis properti trek, termasuk bpm.

Ada ekstensi yang menganalisis segala macam hal tentang lagu, dan akan menemukan lagu yang mirip dengan lagu yang Anda mainkan. Itu disebut Mirage , dan saya menggunakannya untuk sementara waktu, tetapi saya tidak menggunakannya lagi, karena saya telah membuat sejumlah daftar lagu yang sesuai dengan berbagai suasana hati (belum tentu mirip menurut Mirage).

Saya tidak tahu apakah Banshee akan menyimpan bpm yang terdeteksi kembali ke tag "bpm" ID3v2 file tersebut. Jika ada yang tahu cara dengan mudah memeriksa tag bpm dari luar program saya akan memeriksa

Dom
sumber
1

Ini bukan Linux tetapi mungkin bekerja di Wine - Saya menggunakan BMe Analyzer MixMeister

Shevek
sumber
0

Saya menemukan alat lain untuk menandai file MP3 dengan nilai BPM yang benar.

Ini disebut BPMDetect . Sumber terbuka. Lib QT bekerja dengan baik di bawah Gnome. Hadir dengan GUI tetapi dapat dikompilasi sebagai versi konsol saja (jalankan "scons console = 1" seperti yang dinyatakan dalam readme.txt).

Jika tidak, pada akhirnya, saya juga menggunakan "bpmcount" dari BpmDJ karena saya kesulitan untuk mengkompilasi BPMDetect pada host 64 bit Ubuntu (karena ketergantungan fmodex). Jadi saya mengambil skrip shell (sangat keren dan ditulis dengan baik) di atas (lihat di bawah), biner "bpmcount" yang diekstrak dari [x64 .rpm] [3] tersedia di situs web BpmDJ (saya baru saja mengekstrak .rpm dengan

pm2cpio bpmdj-4.2.pl2-0.x86_64.rpm|cpio -idv

dan itu bekerja seperti pesona. Saya hanya perlu memodifikasi skrip di atas sebagai, di luar kotak, itu tidak berfungsi di sisi saya (masalah dengan stdout / stderr dari bpmcount binary). Modifikasi saya adalah tentang pengalihan file:

local bpm=$(bpmcount "$file" 3>&1 1>/dev/null 2>&3 | grep '^[0-9]' | cut -f1)
Sergio
sumber
0

Ada alat lain yang direkomendasikan dalam pertanyaan ini pada stackoverflow: aubio , yang datang bersama dengan modul python.

Saya belum mencobanya karena saya agak sibuk mengurus kompilasi BpmDj . Untuk berjaga-jaga jika ada orang lain yang mengalami kesulitan yang sama saat mencoba, saya ingin sangat merekomendasikan untuk memastikan:

  1. setelah mengunduh rilis terbaru dari sumber BpmDj
  2. memiliki pustaka dorongan yang sesuai diinstal

Dengan pemutakhiran kompilator g ++ terbaru, beberapa masalah tampaknya telah muncul terutama mengenai rilis debian dan ubuntu terbaru. Segera setelah dia menyadari masalah ini, penulis memiliki kebaikan untuk memperbaiki ketidakcocokan yang muncul dan mengumpulkan rilis baru yang sekarang dikompilasi seperti pesona. Jadi siapa pun yang hampir putus asa karena kesalahan kompilasi tanpa akhir-akhir ini: Anda selamat sekarang.

@ mmx , alat Anda terlihat bagus juga, tetapi mereka bergantung SoX, yang secara default tidak memiliki fitur mp3. Jadi mereka memerlukan kompilasi SoX dengan dukungan Lame / MAD terlebih dahulu, yang sayangnya terlalu banyak upaya untuk orang-orang yang malas seperti saya.

J. Katzwinkel
sumber
0

Untuk membuat solusi @meridius bekerja pada Mac saya, saya harus melakukan sedikit kerja keras ekstra dan memodifikasi skripnya:

# Let's install bpm-tools
git clone http://www.pogo.org.uk/~mark/bpm-tools.git
cd bpm-tools
make && make install
# There will be errors, but they did not affect the result

# The following three lines could be replaced by including this directory in your $PATH
ln -s <absolute path to bpm-tools>/bpm /usr/local/bin/bpm
ln -s <absolute path to bpm-tools>/bpm-tag /usr/local/bin/bpm-tag
ln -s <absolute path to bpm-tools>/bpm-graph /usr/local/bin/bpm-graph
cd ..

# Time to install a bunch of GNU tools
# Not all of these packages are strictly necessary for this script, but I decided I wanted the whole GNU toolchain in order to avoid this song-and-dance in the future
brew install coreutils findutils gnu-tar gnu-sed gawk gnutls gnu-indent gnu-getopt bash flac vorbis-tools
brew tap homebrew/dupes; brew install grep

# Now for Mutagen (contains mid3v2)
git clone https://github.com/nex3/mutagen.git
cd mutagen
./setup.py build
sudo ./setup.py install
# There will be errors, but they did not affect the result
cd ..

Kemudian saya harus memodifikasi skrip untuk menunjuk ke versi GNU segalanya, dan beberapa tweak lainnya:

#!/usr/local/bin/bash

# ================================= FUNCTIONS =================================

function help() {
    less <<< 'BPMWRAP

Description:
    This BASH script is a wrapper for bpm-tag utility of bpm-tools and several
    audio tagging utilities. The purpose is to make BPM (beats per minute)
    tagging as easy as possible.
    Default behaviour is to look through working directory for *.mp3 files
    and compute and print their BPM in the following manner:
        [current (if any)] [computed] [filename]

Usage:
    bpmwrap [options] [directory or filenames]

Options:
    You can specify files to process by one of these ways:
        1) state files and/or directories containing them after options
        2) specify --import file
        3) specify --input file
    With either way you still can filter the resulting list using --type option(s).
    Remember that the script will process only mp3 files by default, unless
    specified otherwise!

    -i, --import file
        Use this option to set BPM tag for all files in given file instead of
        computing it. Expected format of every row is BPM number and absolute path
        to filename separated by semicolon like so:
            145;/home/trinity/music/Apocalyptica/07 beyond time.mp3
        Remember to use --write option too.
    -n, --input file
        Use this option to give the script list of FILES to process INSTEAD of paths
        where to look for them. Each row whould have one absolute path.
        This will bypass the searching part and is that way useful when you want
        to process large number of files several times. Like when you are not yet
        sure what BPM limits to set. Extension filtering will still work.
    -o, --output file
        Save output also to a file.
    -l, --list-save file
        Save list of files about to get processed. You can use this list later
        as a file for --input option.
    -t, --type filetype
        Extension of file type to work with. Defaults to mp3. Can be specified
        multiple times for more filetypes. Currently supported are mp3 ogg flac.
    -e, --existing-only
        Only show BPM for files that have it. Do NOT compute new one.
    -w, --write
        Write computed BPM to audio file but do NOT overwrite existing value.
    -f, --force
        Write computed BPM to audio file even if it already has one. Aplicable only
        with --write option.
    -m, --min minbpm
        Set minimal BPM to look for when computing. Defaults to bpm-tag minimum 84.
    -x, --max maxbpm
        Set maximal BPM to look for when computing. Defaults to bpm-tag maximum 146.
    -v, --verbose
        Show "progress" messages.
    -c, --csv-friendly
        Use semicolon (;) instead of space to separate output columns.
    -h, --help
        Show this help.

Note:
    Program bpm-tag (on whis is this script based) is looking only for lowercase
    file extensions. If you get 0 (zero) BPM, this should be the case. So just
    rename the file.

License:
    GPL V2

Links:
    bpm-tools (http://www.pogo.org.uk/~mark/bpm-tools/)

Dependencies:
    bpm-tag mid3v2 vorbiscomment metaflac

Author:
    Martin Lukeš ([email protected])
    Based on work of kolypto (http://superuser.com/a/129157/137326)
    '
}

# Usage: result=$(inArray $needle haystack[@])
# @param string needle
# @param array haystack
# @returns int (1 = NOT / 0 = IS) in array
function inArray() {
    needle="$1"
    haystack=("${!2}")
    out=1
    for e in "${haystack[@]}" ; do
        if [[ "$e" = "$needle" ]] ; then
            out=0
            break
        fi
    done
    echo $out
}

# Usage: result=$(implode $separator array[@])
# @param char separator
# @param array array to implode
# @returns string separated array elements
function implode() {
    separator="$1"
    array=("${!2}")
    IFSORIG=$IFS
    IFS="$separator"
    echo "${array[*]}"
    IFS=$IFSORIG
}

# @param string file
# @returns int BPM value
function getBpm() {
    local file="$1"
    local ext="${file##*.}"
    declare -l ext # convert to lowercase
    { case "$ext" in
        'mp3')  mid3v2 -l "$file" ;;
        'ogg')  vorbiscomment -l "$file" ;;
        'flac') metaflac --export-tags-to=- "$file" ;;
    esac ; } | fgrep 'BPM=' -a | cut -d'=' -f2
}

# @param string file
# @param int BPM value
function setBpm() {
    local file="$1"
    local bpm="${2%%.*}"
    local ext="${file##*.}"
    declare -l ext # convert to lowercase
    case "$ext" in
        'mp3')  mid3v2 --TBPM "$bpm" "$file" ;;
        'ogg')  vorbiscomment -a -t "BPM=$bpm" "$file" ;;
        'flac') metaflac --set-tag="BPM=$bpm" "$file"
            mid3v2 --TBPM "$bpm" "$file" # Need to store to ID3 as well :(
        ;;
    esac
}

# # @param string file
# # @returns int BPM value
function computeBpm() {
    local file="$1"
    local m_opt=""
    [ ! -z "$m" ] && m_opt="-m $m"
    local x_opt=""
    [ ! -z "$x" ] && x_opt="-x $x"
    local row=$(bpm-tag -fn $m_opt $x_opt "$file" 2>&1 | fgrep "$file")
    echo $(echo "$row" \
        | gsed -r 's/.+ ([0-9]+\.[0-9]{3}) BPM/\1/' \
        | gawk '{printf("%.0f\n", $1)}')
}

# @param string file
# @param int file number
# @param int BPM from file list given by --import option
function oneThread() {
    local file="$1"
    local filenumber="$2"
    local bpm_hard="$3"
    local bpm_old=$(getBpm "$file")
    [ -z "$bpm_old" ] && bpm_old="NONE"
    if [ "$e" ] ; then # only show existing
        myEcho "$filenumber/$NUMFILES${SEP}$bpm_old${SEP}$file"
    else # compute new one
        if [ "$bpm_hard" ] ; then
            local bpm_new="$bpm_hard"
        else
            local bpm_new=$(computeBpm "$file")
        fi
        [ "$w" ] && { # write new one
            if [[ ! ( ("$bpm_old" != "NONE") && ( -z "$f" ) ) ]] ; then
                setBpm "$file" "$bpm_new"
            else
                [ "$v" ] && myEcho "Non-empty old BPM value, skipping ..."
            fi
        }
        myEcho "$filenumber/$NUMFILES${SEP}$bpm_old${SEP}$bpm_new${SEP}$file"
    fi
}

function myEcho() {
    [ "$o" ] && echo -e "$1" >> "$o"
    echo -e "$1"
}


# ================================== OPTIONS ==================================

eval set -- $(/usr/local/Cellar/gnu-getopt/1.1.6/bin/getopt -n $0 -o "-i:n:o:l:t:ewfm:x:vch" \
    -l "import:,input:,output:,list-save:,type:,existing-only,write,force,min:,max:,verbose,csv-friendly,help" -- "$@")

declare i n o l t e w f m x v c h
declare -a INPUTFILES
declare -a INPUTTYPES
while [ $# -gt 0 ] ; do
    case "$1" in
        -i|--import)                shift ; i="$1" ; shift ;;
        -n|--input)                 shift ; n="$1" ; shift ;;
        -o|--output)                shift ; o="$1" ; shift ;;
        -l|--list-save)         shift ; l="$1" ; shift ;;
        -t|--type)                  shift ; INPUTTYPES=("${INPUTTYPES[@]}" "$1") ; shift ;;
        -e|--existing-only) e=1 ; shift ;;
        -w|--write)                 w=1 ; shift ;;
        -f|--force)                 f=1 ; shift ;;
        -m|--min)                       shift ; m="$1" ; shift ;;
        -x|--max)                       shift ; x="$1" ; shift ;;
        -v|--verbose)               v=1 ; shift ;;
        -c|--csv-friendly)  c=1 ; shift ;;
        -h|--help)                  h=1 ; shift ;;
        --)                                 shift ;;
        -*)                                 echo "bad option '$1'" ; exit 1 ;; #FIXME why this exit isn't fired?
        *)                                  INPUTFILES=("${INPUTFILES[@]}" "$1") ; shift ;;
    esac
done


# ================================= DEFAULTS ==================================

#NOTE Remove what requisities you don't need but don't try to use them after!
#         always  mp3/flac     ogg       flac
REQUIRES="bpm-tag mid3v2 vorbiscomment metaflac"
which $REQUIRES > /dev/null || { myEcho "These binaries are required: $REQUIRES" >&2 ; exit 1; }

[ "$h" ] && {
    help
    exit 0
}

[[ $m && $x && ( $m -ge $x ) ]] && {
    myEcho "Minimal BPM can't be bigger than NOR same as maximal BPM!"
    exit 1
}
[[ "$i" && "$n" ]] && {
    echo "You cannot specify both -i and -n options!"
    exit 1
}
[[ "$i" && ( "$m" || "$x" ) ]] && {
    echo "You cannot use -m nor -x option with -i option!"
    exit 1
}
[ "$e" ] && {
    [[ "$w" || "$f" ]] && {
        echo "With -e option you don't have any value to write!"
        exit 1
    }
    [[ "$m" || "$x" ]] && {
        echo "With -e option you don't have any value to count!"
        exit 1
    }
}

for file in "$o" "$l" ; do
    if [ -f "$file" ] ; then
        while true ; do
            read -n1 -p "Do you want to overwrite existing file ${file}? (Y/n): " key
            case "$key" in
                y|Y|"") echo "" > "$file" ; break ;;
                n|N)        exit 0 ;;
            esac
            echo ""
        done
        echo ""
    fi
done

[ ${#INPUTTYPES} -eq 0 ] && INPUTTYPES=("mp3")

# NUMCPU="$(ggrep ^processor /proc/cpuinfo | wc -l)"
NUMCPU="$(sysctl -a | ggrep machdep.cpu.core_count | gsed -r 's/(.*)([0-9]+)(.*)/\2/')"
LASTPID=0
TYPESALLOWED=("mp3" "ogg" "flac")
# declare -A BPMIMPORT # array of BPMs from --import file, keys are file names
declare -A BPMIMPORT # array of BPMs from --import file, keys are file names

for type in "${INPUTTYPES[@]}" ; do
    [[ $(inArray $type TYPESALLOWED[@]) -eq 1 ]] && {
        myEcho "Filetype $type is not one of allowed types (${TYPESALLOWED[@]})!"
        exit 1
    }
done

### here are three ways how to pass files to the script...
if [ "$i" ] ; then # just parse given file list and set BPM to listed files
    if [ -f "$i" ] ; then
        # myEcho "Setting BPM tags from given file ..."
        while read row ; do
            bpm="${row%%;*}"
            file="${row#*;}"
            ext="${file##*.}"
            ext="${ext,,}" # convert to lowercase
            if [ -f "$file" ] ; then
                if [ $(inArray $ext INPUTTYPES[@]) -eq 0 ] ; then
                    FILES=("${FILES[@]}" "$file")
                    BPMIMPORT["$file"]="$bpm"
                else
                    myEcho "Skipping file on row $rownumber (unwanted filetype $ext) ... $file"
                fi
            else
                myEcho "Skipping non-existing file $file"
            fi
        done < "$i"
    else
        myEcho "Given import file does not exists!"
        exit 1
    fi
elif [ "$n" ] ; then # get files from file list
    if [ -f "$n" ] ; then
        rownumber=1
        while read file ; do
            if [ -f "$file" ] ; then
                ext="${file##*.}"
                ext="${ext,,}" # convert to lowercase
                if [ $(inArray $ext INPUTTYPES[@]) -eq 0 ] ; then
                    FILES=("${FILES[@]}" "$file")
                else
                    myEcho "Skipping file on row $rownumber (unwanted filetype $ext) ... $file"
                fi
            else
                myEcho "Skipping file on row $rownumber (non-existing) ... $file"
            fi
            let rownumber++
        done < "$n"
        unset rownumber
    else
        myEcho "Given input file $n does not exists!"
        exit 1
    fi
else # get files from given parameters
    [ ${#INPUTFILES[@]} -eq 0 ] && INPUTFILES=`pwd`
    for file in "${INPUTFILES[@]}" ; do
        [ ! -e "$file" ] && {
            myEcho "File or directory $file does not exist!"
            exit 1
        }
    done
    impl_types=`implode "|" INPUTTYPES[@]`
    while read file ; do
        echo -ne "Creating list of files ... (${#FILES[@]}) ${file}\033[0K"\\r
        FILES=("${FILES[@]}" "$file")
    done < <(gfind "${INPUTFILES[@]}" -type f -regextype posix-awk -iregex ".*\.($impl_types)")
    echo -e "Counted ${#FILES[@]} files\033[0K"\\r
fi

[ "$l" ] && printf '%s\n' "${FILES[@]}" > "$l"

NUMFILES=${#FILES[@]}
FILENUMBER=1

[ $NUMFILES -eq 0 ] && {
    myEcho "There are no ${INPUTTYPES[@]} files in given files/paths."
    exit 1
}

declare SEP=" "
[ "$c" ] && SEP=";"


# =============================== MAIN SECTION ================================

if [ "$e" ] ; then # what heading to show
    myEcho "num${SEP}old${SEP}filename"
else
    myEcho "num${SEP}old${SEP}new${SEP}filename"
fi

for file in "${FILES[@]}" ; do
    [ `jobs -p | wc -l` -ge $NUMCPU ] && wait
    [ "$v" ] && myEcho "Parsing (${FILENUMBER}/${NUMFILES})\t$file ..."
    oneThread "$file" "$FILENUMBER" "${BPMIMPORT[$file]}" &
    LASTPID="$!"
    let FILENUMBER++
done

[ "$v" ] && myEcho "Waiting for last process ..."
wait $LASTPID
[ "$v" ] && myEcho \\n"DONE"

Terima kasih atas kerja keras Anda @kolypto dan @meridius.

... rasa sakit yang saya alami untuk mempertahankan alur kerja CLI dan tidak membayar uang untuk alat musik ...

Adrian
sumber