"DX7_AllTheWeb" durchsuchen mit Perl

P

PySeq

|||||
Hi,

hier ein weiteres Perl-Skript. Es gibt ja diese DX7-Patch-Sammlung "alltheweb". Die ".zip"-Datei wird zu einem Verzeichnis "DX7_AllTheWeb" mit zahlreichen Unterverzeichnissen entpackt, in denen sich viele ".SYX"-Dateien befinden.
Aber in welcher Dateien befindet sich jetzt ein bestimmter Patch, den man (anhand des Namens) sucht?

Dazu das Skript. Man tut es in das Verzeichnis "DX7_AllTheWeb". Oder in eins der Unterverzeichnisse. Bei "Big Mamma" ist z.B. viel zu finden, man kann das Skript also auch in "../DX7_AllTheWeb/Big Mamma" tun, und dann da ausführen.
Den Patch-Namen gibt man mit, also z.B. "./finddx7patch.pl jazz".

Das Skript sucht dann in dem Verzeichnis und in allen Unterverzeichnissen nach ".SYX"-Dateien, führt auf diesen den bash-Befehl "strings" aus, erhält so die ASCII-Inhalte innerhalb der Dateien und gleicht diese mit dem Suchstring ab.
Wenn es Übereinstimmungen findet, gibt es die Dateinamen aus (und wenn man als Zweites noch die Option "-v" für "verbose" mitgibt, auch die gefundenen Strings). Das ist nützlich. :)

(Alternativ könnte man auch was mit bashs "grep" bauen, aber ich fand's so schöner.)

Perl:
#!/usr/bin/perl

use warnings;
use strict;

my $program_description = q(

finddx7patch.pl

(C) 2019, PySeq. Licence: GNU GPL version 2.

Searches inside ".SYX"-files for strings (names of DX7-patches).

Start this script inside the "../DX7_AllTheWeb"-directory, or
for example in "../DX7_AllTheWeb/Big Mamma", if you want to
search for DX7-patches just in that directory.

-----

GNU GPL copyright notice:

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>. );


use File::Find;
use Cwd;

my $SEARCHSTRING;
my @OVERALLFOUND;

if ($#ARGV < 0) {
    print "\nUsage: finddx7patch.pl SEARCHSTRING\n\n";
    exit 1;
} else {
    $SEARCHSTRING = $ARGV[0];
}

my $VERBOSE = 0;
if ($#ARGV >= 1 && $ARGV[1] eq "-v") {
    $VERBOSE = 1;
}

sub wanted {
    my $name = $File::Find::name;
    if ($name !~ m/SYX$/i) {
        return;
    }
    my @a = `strings "$name"`;
    my @found = ();
    my $i;
    for $i (@a) {
        chomp($i);
        if ($i =~ m/$SEARCHSTRING/i) {
            push(@found, $i);
        }
    }
    if ($#found >= 0) {
         print "$name\n";
         push(@OVERALLFOUND, $name);
         if ($VERBOSE) {
             for $i (@found) {
                 print "$i\n";
             }
         }
         if ($VERBOSE) {
             print "\n";
         }
    }
}

my $dir = getcwd();
print "\n";
find(\&wanted, $dir);
if ($#OVERALLFOUND == -1) {
    print "Sorry, \"$SEARCHSTRING\" not found in the DX7-files.\n\n";
} elsif (! $VERBOSE) {
    print "\n";
}
 
Zuletzt bearbeitet:
Wenn Du weißt wie der Patch heißt:
find . -type f -name GENAUER-NAME.syx

Wenn Du es nicht genau weißt:
find . -type f | grep -i ungef*hr.syx
 
find . -type f | grep -i ungef*hr.syx
Hmm, wo ist denn da der Patch-Name (z.B. "JAZZ GUITAR" oder so)? Die SYX da heißen ja nicht "JAZZ_GUITAR.SYX", sondern z.B. "NEWFIL48.SYX", und irgendwo darin ist ein String "JAZZ GUIT".

Aber grundsätzlich könnte man es schon mit find und grep machen. Ich fand's wie gesagt so (s.o.) schöner, ich würde 'eh ein Skript machen, weil ich mir keine kryptischen find-Befehle merken wollen würde.

'grep -ir "JAZZ" *' ginge theoretisch, aber die Ausgabe ist relativ unübersichtlich.
 
Zuletzt bearbeitet:
$time find . | grep -i stroud
./Bridge Music Recording Studio/Sysex/Set 20 Collection Specific/M Stroud
./Bridge Music Recording Studio/Sysex/Set 20 Collection Specific/M Stroud/M_STROUD.SYX
./Dexed v1_0 (Black Winny)/Mike Stroud
./Dexed v1_0 (Black Winny)/Mike Stroud/DX7_v34.txt
./Dexed v1_0 (Black Winny)/Mike Stroud/M_STROUD.SYX
./Mike Stroud
./Mike Stroud/M_STROUD.SYX


real 0m0,088s
user 0m0,017s
sys 0m0,032s



versus

$time perl ./finddx7patch.pl stroud

strings: ‚/media/florian/HD1TBext/privat/synths/yamaha/DX7_AllTheWeb/Bridge Music Recording Studio/Sysex/Set 31 Unsorted/dx-7_variety_b/.SYX‛: Keine solche Datei
strings: Warnung: »/media/florian/HD1TBext/privat/synths/yamaha/DX7_AllTheWeb/Bridge Music Recording Studio/Sysex/Set 31 Unsorted/dx7romcartrige.syx« ist ein Verzeichnis
strings: ‚/media/florian/HD1TBext/privat/synths/yamaha/DX7_AllTheWeb/Dave Benson/.SYX‛: Keine solche Datei
strings: ‚/media/florian/HD1TBext/privat/synths/yamaha/DX7_AllTheWeb/Dexed v1_0 (Black Winny)/Jeff Saxe/.SYX‛: Keine solche Datei
Sorry, "stroud" not found in the DX7-files.



real 0m27,057s
user 0m19,898s
sys 0m5,399s

hmm, 10tel Sekunde mit 7 Treffern versus halbe Minute ohne treffer - da geht noch was... ;-)
 
Hmm, wo ist denn da der Patch-Name (z.B. "JAZZ GUITAR" oder so)?
Ach so, Du willst in den SYX-Files suchen. Dann:

$find . -type f -exec grep -ail JAZZ*GUITAR {} \;
./Aminet/73.syx
./Atari/DX7_A14.SYX
./Big Mamma/100 through 360/NEWFI162.SYX
./Bridge Music Recording Studio/DX1/Bank0009.syx
./Bridge Music Recording Studio/Sysex/Set 12 TX7/TX7-1/TX7-12.SYX
./Bridge Music Recording Studio/Sysex/Set 16 Banks/Bank0009.syx
./Bridge Music Recording Studio/Sysex/Set 18 SoundSations/056.SYX
./Bridge Music Recording Studio/Sysex/Set 18 SoundSations/106.SYX
./Bridge Music Recording Studio/Sysex/Set 20 Collection Specific/JC Magro/patamix.syx
./Bridge Music Recording Studio/Sysex/Set 29 Various/Pat/pat 8.SYX
./Bridge Music Recording Studio/Sysex/Set 31 Unsorted/dx-7_variety_b/DX7MD7.SYX
./Bridge Music Recording Studio/Sysex/Set 31 Unsorted/DX7 Sounds Sysex/BANK0009.SYX
./Bridge Music Recording Studio/Sysex/Set 31 Unsorted/DX7 SYSEX PATCHES/DX OWNER BANKS A/BANK0009.SYX
./Bridge Music Recording Studio/Sysex/Set 31 Unsorted/Yamaha_DX7_syx1/Bank0009.syx
./Bridge Music Recording Studio/Sysex/Set 4 Instruments/Guitar/Guitar2/GUITAR05.SYX
./Bridge Music Recording Studio/Sysex/Set 6 DX7/DX7-1/DX7_A14.SYX
./Bridge Music Recording Studio/Sysex/Set 6 DX7/DX7-2/DX7MD7.SYX
./Bridge Music Recording Studio/Sysex/Set 6 DX7/DX7-5/Dx106.syx
./Chris Dodunski/Bank0009.syx
./Dave Benson/DX7MD7.SYX
./Dexed v1_0 (Black Winny)/!Instruments/Misc/Bank0009.syx
./Dexed v1_0 (Black Winny)/!Instruments/Misc/Dx106.syx
./Dexed v1_0 (Black Winny)/!Instruments/Misc/DX7_A14.SYX
./Dexed v1_0 (Black Winny)/!Instruments/Plucked/Guitar/Guitar2/GUITAR05.SYX
./Dexed v1_0 (Black Winny)/!Unsorted/dx7zicweb/BANK0009.SYX
./Dexed v1_0 (Black Winny)/Aminet/073.syx
./Dexed v1_0 (Black Winny)/Big Mamma/BIGMAMMA162.SYX
./Dexed v1_0 (Black Winny)/Christopher Pardy (Pat)/pat 08.SYX
./Dexed v1_0 (Black Winny)/Juan Carlos Magro/patamix.syx
./Hitaye/Dx106.syx
./Juan Carlos Magro/patamix.syx
./LiVeMuSiC/TX80.SYX
./LiVeMuSiC/WEDING2.SYX
./Stephen Ibsen/instrument/guitar/GUITAR05.SYX
./Tim Garrett/TX7-12.SYX

dauert 13 Sekunden
 
Kann man wie gesagt machen.
Ich kann mir bei "find" nie dieses "{} \" merken (und was es tun soll), und würde das allein schon deshalb in einem Skript kapseln. Was dann auch nicht viel anders aussehen würde.
Man will ja nur den gesuchten Sound haben. Deshalb muß man nur selten die ganze Kollektion durchsuchen, was dann vielleicht 30 Sekunden dauern würde. Meist findet man das Gesuchte aber schon in "Big Mamma", nach 3 Sekunden oder so.
Insofern ist das nicht tragisch, wenn das Skript ein bißchen langsamer ist als die C-Befehle aus bash.

In bash gibt es oft Probleme mit Dateinamen, die Leerzeichen oder Umlaute enthalten, vor allem in Variablen in einem Skript. Perl und Python haben für den Programmierer den Vorteil, daß sich Strings da so verhalten, wie man es erwartet (mal abgesehen von den Problemen mit Encodings, Unicode, usw.). Deshalb setze ich das lieber ein, wenn es um Dateinamen geht, da hab' ich die Sache besser unter Kontrolle.

Wenn ich auf jeder Datei einzeln "strings" aufrufe, ist das natürlich langsam. Das ist mir schon klar, macht mir in dem Fall aber nichts aus.

".../Jeff Saxe/.SYX", usw. scheinen mir übrigens keine gültigen Dateinamen zu sein. Da müßte vor dem ".SYX" doch eigentlich was sein.
 
Zuletzt bearbeitet:
Ich kann mir bei "find" nie dieses "{} \" merken (und was es tun soll),

"{}" stellt das ergebnis der find-Zeile dar, und das "\;" zeigt das Ende der exec-Option an

Prinzip
-exec BEFEHL {} GGF_RESTBEFEHL \;

Das wäre bei einer konkreten Datei
ls -l ./Stephen Ibsen/instrument/guitar/GUITAR05.SYX >> liste.txt

Und innerhalb von siehts dann so aus:
find . -type f -exec ls -l {} >> liste.txt \;
 
Wahrscheinlich fehlte mir einfach die "-a"-Option von grep, die kannte ich noch nicht. Da ich aber auch keine Lust habe, mir die zu merken und was man sonst noch braucht, würde ich das dann in bash so schreiben:
Bash:
#!/bin/bash

# finddx7patch.sh

searchstring=""

if test "$#" -eq 0
then
    echo -e "\nUsage: finddx7patch.sh searchstring\n"
    exit 1
else
    searchstring="$1"
fi

found=$(grep -airl "$searchstring" .)
nr_found=$(echo -n "$found" | wc -l)

if test "$nr_found" -eq 0
then
    echo -en "\nSorry, \"$searchstring\" not found in the DX7-files.\n\n";
else
    echo -en "\n$found\n\n"
fi
Wobei ich dann wieder diesen mehrzeiligen Output in einer Variablen hätte, der immer so schwer zu kontrollieren ist (weil diese Variablen dafür eigentlich nicht gemacht sind).
Und ich auch nicht sehe, daß das die bessere Lösung gegenüber dem Perl-Vorschlag sein soll.
Schneller vielleicht - kommt wie gesagt hier nicht drauf an.

Ich mag bash nicht: Es ist alles so steif, und man kann unter Umständen nur das machen, was die Befehle einem in ihren Optionen vorgeben (wobei man sich erstmal zig Optionen angucken muß). Und manchmal verhält es sich auch noch unvorhergesehen, etwa wenn Subshells im Spiel sind, und plötzlich Variablen nicht mehr bekannt sind. Das ist alles relativ unerfreulich, und man hat das alles wie gesagt in Perl und Python nicht.
Deshalb schreibe ich lieber in diesen Sprachen. Ich gebe zu, hier kann man das Problem mit einem einzigen "grep"-Befehl lösen. Dessen Optionen man sich aber merken müßte (wozu ich wie gesagt keine Lust hab').
Ich setze z.B. auch ein Skript zur Mehrwertsteuer ein, um vom Brutto aus das Netto auszurechnen, weil ich keine Lust hab', mir jedesmal zu merken, wie das geht. Ich will hier einfach sagen: "Hier ist das Brutto, gib' mir das Netto". Und so will ich auch sagen: "So müßte der DX7-Patch heißen, gib' mir die Datei, in der der ist".
Ohne groß über "grep -a" oder "grep -b" oder "find ... {} \;" oder wasauchimmer nachzudenken. Ich hoffe, so wird klarer, worum es mir geht.
 
Zuletzt bearbeitet:


News

Zurück
Oben