Eine bash script Variable veraendert sich - nur wieso.... :)

Uzer1510

Ensign
Registriert
Feb. 2025
Beiträge
205
Ich hab mit mal ein bash script gehäkelt das MP3s aus Einzeltracks zusammenfasst und nach 128 CBR konvertiert und halt wnen vorhanden aus den Einzeltracks das Cover extrahiert und später wieder einrechnet (per ffmpeg)

Das tut alles wie gewünscht - aber ich habe eine Sache die mich irgendwie nervt :D und ich mit so nem dirty fix behebe... ich wüsste aber gern warum....

der Teil des Scriptes das definitiv den Fehler hat

wie man sieht muss ich $safe_file um ein führendes "/" ergänzen - das ist aber NUR dann 1x fällig nachdem vorher if [ -z "$COVER_IMAGE" ]; then
durchlaufen wurde - sonst nie und auch nur bei der einen Datei direkt dahinter....

irgendwie sehe ich nicht wo $file verändert werden würde?

Code:
while IFS= read -r -d '' file; do
    # ersetze ' durch _ im Namen wegen ffmpeg
    safe_file=$(echo "$file" | sed "s/['\"]/_/g")

    if [ "$file" != "$safe_file" ]; then
        mv "$file" "$safe_file"
    fi

    if $ALL_128_CBR; then
       # auf 128 KBit testen
       BITRATE=$(ffprobe -v error -select_streams a:0 -show_entries format=bit_rate -of default=noprint_wrappers=1:nokey=1 "$safe_file")
       BITRATE=$((BITRATE / 1000))

       # auf vbr testen
       VBR_DETECTED=$(ffprobe -v error -select_streams a:0 -show_entries format_tags=encoder -of default=noprint_wrappers=1:nokey=1 "$safe_file" | grep -i "VBR")

       # teste ob evtl alle Dateien schon 128 CBR sind - dann nur zusammenfuegen, sonst reencoden
       if [ "$BITRATE" -ne 128 ] || [ -n "$VBR_DETECTED" ]; then
          ALL_128_CBR=false
          MYTEMPNAME="$(basename "${safe_file}")"
          echo "* Datei hat andere Bitrate ${BITRATE} kb/s (Dateiname: ${MYTEMPNAME})"
       fi
    fi

    if [[ $safe_file != /* ]]; then
       safe_file="/$safe_file"
       echo "* der Pfad von $safe_file musste angepasst werden  :O :O ????  Voll der Pfusch"
    fi


    if [ ! -f "$safe_file" ]; then
       echo "* Fehler Datei nicht vorhanden: $safe_file"
       echo ""
       echo ""
       echo "ABBRUCH"
       echo ""
       echo ""
       exit 3
    fi

    echo "file '$safe_file'" >> "$TEMP_LIST"

    if [ -z "$COVER_IMAGE" ]; then

       #teste ob ein Bild integriert ist wenn ja das nutzen
       VIDEO_PRESENT=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_type -of csv=p=0 "$safe_file")

       if [ "$VIDEO_PRESENT" = "video" ]; then
          if ! [ -f "${INPUT_DIR}/${TEMPIMAGEFILE}" ]; then
             ffmpeg -y -i "$safe_file" -map 0:v:0 -c copy "${INPUT_DIR}/${TEMPIMAGEFILE}"
             if [ -f "${INPUT_DIR}/${TEMPIMAGEFILE}" ]; then
                COVER_IMAGE="${INPUT_DIR}/${TEMPIMAGEFILE}"
                echo "* Coverbild gefunden benutze das"
              fi
          fi
       fi
    fi


done < <(find "$INPUT_DIR" -maxdepth 1 -type f -name "*.mp3" -print0 | sort -z)
 
Zuletzt bearbeitet:
Ich sehe es spontan auch nicht. Aber als Tipp: Schreib mal vor deine Schleife eine Zeile: set -x

Damit aktivierst du eine Debug-Ausgabe, die dir jeden ausgeführten Befehl anzeigt. Das gibt bei so einem Skript ziemlich viel Output, sollte aber für dich nachvollziehbar machen, was genau passiert.
 
  • Gefällt mir
Reaktionen: KillerCow
oh ok das kannte ich noch gar nicht ich habe bisher immer viel echos gemacht :D

----

Hm es fehlt einfach das führende "/" bei $file..... nachdem ich das Bild ausgelesen habe, der Rest von $file ist aber korrekt... das schon irgendwie komisch (und zwar nur dann wenn das Bild ausgelesen wird, sonst passt es in späteren Durchläufen der Schleife wieder)

Aber was kann denn das $file für einen Durchgang "nachträglich" ändern? das wird doch sicher schon im bash Schleifen Speicher sein?

Wenn ich das Extrahieren des Bildes auskommentiere dann laeuft es ohne Korrektur durch also den Teil hier

Code:
             ffmpeg -y -i "$safe_file" -map 0:v:0 -c copy "${INPUT_DIR}/${TEMPIMAGEFILE}"           
             if [ -f "${INPUT_DIR}/${TEMPIMAGEFILE}" ]; then              
                     COVER_IMAGE="${INPUT_DIR}/${TEMPIMAGEFILE}"
                     echo "* Coverbild gefunden benutze das"
            fi
 
Zuletzt bearbeitet:
Ist das der ganze Code oben oder nur ein Teil des Codes?
Ergänzung ()

stefan92x schrieb:
Ich sehe es spontan auch nicht. Aber als Tipp: Schreib mal vor deine Schleife eine Zeile: set -x
Noch genauer, set -vx, oder rufe das Script auf mit bash -vx Scriptname.

Interessiert Dich jetzt nur der Fehler oder auch Tipps zu Deinem Script?
 
Zuletzt bearbeitet:
Uzer1510 schrieb:
der Teil des Scriptes das definitiv den Fehler hat
Du musst schon alles posten um nach dem Fehler zu suchen.
 
Glaube nicht dass das Sinn machtr das ganz Script zu posten der Fehler findet ja komplett inerhalb der einen while Schleife stat die keine bash functions nutzt die irgendeine Variable ändern würden

Code:
#!/bin/bash

if [ "$#" -ne 2 ]; then
    echo "Idiot, das script braucht Parameter $0 <input_directory> <target_directory>"
    exit 1
fi

INPUT_DIR="$1"
TARGET_DIR="$2"

INPUT_DIR="${INPUT_DIR%/}"
TARGET_DIR="${TARGET_DIR%/}"

TEMPIMAGEFILE="myEmbeddedImage.jpg"

check_if_running() {

  local script_name
  script_name="$(basename "$0")"

  local matching_pids
 
  echo "* test ob script schon laeuft...."
 
  matching_pids="$(pgrep -f "$script_name")"

  local count
  count="$(echo "$matching_pids" | wc -l)"

  if [[ "$count" -gt 1 ]] || ([[ "$count" -eq 1 ]] && [[ "$matching_pids" != "$$" ]]); then
    echo "das rennt schon"
    exit 1
  fi
}


echo ""
echo ""
echo ""
echo "-----------------------------------------------------------------------------"
echo $0
echo ""
echo "Quelle: $1"
echo "Ziel: $2"
echo "-----------------------------------------------------------------------------"


check_if_running


if [ ! -d "$INPUT_DIR" ]; then
    echo "Quellverzeichnis '$INPUT_DIR' nicht vorhanden."
    echo ""
    echo ""
    exit 1
fi

mkdir -p "$TARGET_DIR"

# ' und " ersetzen
SANITIZED_DIR=$(echo "$INPUT_DIR" | sed "s/['\"]/_/g")
if [ "$INPUT_DIR" != "$SANITIZED_DIR" ]; then
    mv "$INPUT_DIR" "$SANITIZED_DIR"
    INPUT_DIR="$SANITIZED_DIR"
    echo "* $INPUT_DIR umbenannt"
fi

DIR_NAME=$(basename "$INPUT_DIR")
OUTPUT_FILE="${TARGET_DIR}/${DIR_NAME}.mp3"
echo "* MP3 Zielname $OUTPUT_FILE"
rm -f "$OUTPUT_FILE"


rm -f "${INPUT_DIR}/${TEMPIMAGEFILE}"

COVER_IMAGE=

# MP3-Dateiliste
TEMP_LIST=$(mktemp)


# falls alle bereits 128 CBR nur kein neucodieren
ALL_128_CBR=true



while IFS= read -r -d '' file; do
    # ersetze ' durch _ im Namen wegen ffmpeg
   safe_file=$(echo "$file" | sed "s/['\"]/_/g")
   if [ "$file" != "$safe_file" ]; then
           mv "$file" "$safe_file"
   fi

   if $ALL_128_CBR; then
      # auf 128 KBit testen
      BITRATE=$(ffprobe -v error -select_streams a:0 -show_entries format=bit_rate -of default=noprint_wrappers=1:nokey=1 "$safe_file")
     BITRATE=$((BITRATE / 1000))
     # auf vbr testen
     VBR_DETECTED=$(ffprobe -v error -select_streams a:0 -show_entries format_tags=encoder -of default=noprint_wrappers=1:nokey=1 "$safe_file" | grep -i "VBR")

# teste ob evtl alle Dateien schon 128 CBR sind - dann nur zusammenfuegen, sonst reencoden

 if [ "$BITRATE" -ne 128 ] || [ -n "$VBR_DETECTED" ]; then
       ALL_128_CBR=false
        MYTEMPNAME="$(basename "${safe_file}")"
          echo "* Datei hat andere Bitrate ${BITRATE} kb/s (Dateiname: ${MYTEMPNAME})"
       fi
    fi

    if [[ $safe_file != /* ]]; then
       safe_file="/$safe_file"
       echo "* der Pfad von $safe_file musste angepasst werden  :O :O ????  Voll der Pfusch"
    fi


    if [ ! -f "$safe_file" ]; then
       echo "* Fehler Datei nicht vorhanden: $safe_file"
       echo ""
       echo ""
       echo "ABBRUCH"
       echo ""
       echo ""
       exit 3
    fi

    echo "file '$safe_file'" >> "$TEMP_LIST"

    if [ -z "$COVER_IMAGE" ]; then

       #teste ob ein Bild integriert ist wenn ja das nutzen
       VIDEO_PRESENT=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_type -of csv=p=0 "$safe_file")

       if [ "$VIDEO_PRESENT" = "video" ]; then
          if ! [ -f "${INPUT_DIR}/${TEMPIMAGEFILE}" ]; then
             ffmpeg -y -i "$safe_file" -map 0:v:0 -c copy "${INPUT_DIR}/${TEMPIMAGEFILE}"
             if [ -f "${INPUT_DIR}/${TEMPIMAGEFILE}" ]; then
                COVER_IMAGE="${INPUT_DIR}/${TEMPIMAGEFILE}"
                echo "* Coverbild gefunden benutze das"
              fi
          fi
       fi
    fi


done < <(find "$INPUT_DIR" -maxdepth 1 -type f -name "*.mp3" -print0 | sort -z)




# Nachsehen ob da was drin ist
if [ ! -s "$TEMP_LIST" ]; then
    echo "Die Temp Liste ist leer"
    rm -f "$TEMP_LIST"
    echo ""
    echo ""
    exit 1
fi

# Fall nix inder Datei war nachschauen opb irgendein Bild im Verz rumfliegt
if [ -z "$COVER_IMAGE" ]; then
   COVER_IMAGE=$(find "$INPUT_DIR" -maxdepth 1 -type f -iname "*.jpg" | head -n 1)
   if [ ! -z "$COVER_IMAGE" ]; then
      MYTEMPSTRING="$(echo "$COVER_IMAGE" | sed 's#.*/\([^/]\+/[^/]\+\)$#\1#')"
      echo "* Das erstbeste gefundenene Bild wird reingepackt: $MYTEMPSTRING"
   fi
fi


echo "Starte ffmpeg....."
echo ""
echo ""


# alle 128 CBR => zusammenfrickeln
if $ALL_128_CBR; then
    echo "✅ keine Neucodierung..."
    if [ -n  "$COVER_IMAGE" ]; then
        ffmpeg -hide_banner -f concat -safe 0 -i "$TEMP_LIST" -i "$COVER_IMAGE" -map 0:a -map 1 -c copy -disposition:v attached_pic \
              -id3v2_version 3 -metadata:s:v title="Album cover" -metadata:s:v comment="Cover (front)" -y "$OUTPUT_FILE"
    else
        ffmpeg -hide_banner -f concat -safe 0 -i "$TEMP_LIST" -c copy -y "$OUTPUT_FILE"
    fi
else
    echo "⚠️ Muss neu codiert werden mind 1 MP3 ist nicht 128 CBR..."
 
    if [ -n "$COVER_IMAGE" ]; then

       ffmpeg -hide_banner -f concat -safe 0 -i "$TEMP_LIST" \
         -i "$COVER_IMAGE" \
         -map 0:a -map 1 \
         -c:a libmp3lame -b:a 128k\
         -c:v copy \
         -disposition:v attached_pic \
         -metadata:s:v title="Album cover" \
         -metadata:s:v comment="Cover (front)" \
         -id3v2_version 3 \
         -write_id3v1 1 \
         -threads 0 \
         -y "$OUTPUT_FILE"


         #ffmpeg -i "$OUTPUT_FILE" -i "$COVER_IMAGE" -map 0:a -map 1 -c:a copy -disposition:v attached_pic \
         # -id3v2_version 3 -metadata:s:v title="Album cover" -metadata:s:v comment="Cover (front)" -y "$OUTPUT_FILE"

        #  ffmpeg -f concat -safe 0 -i "$TEMP_LIST" -i "$COVER_IMAGE" -map 0:a -map 1:v \
        #       -c:a libmp3lame -b:a 128k -c:v copy -metadata:s:v title="Album cover" \
        #       -metadata:s:v comment="Cover (front)" -id3v2_version 3 -write_id3v1 1 -y "$OUTPUT_FILE"
    else
        ffmpeg -hide_banner -f concat -safe 0 -i "$TEMP_LIST" -acodec libmp3lame -b:a 128k -id3v2_version 3 -write_id3v1 1 -y -threads 0 "$OUTPUT_FILE"
    fi
fi

# sollte passen mit $? ffmpeg letztes Prog
if [ $? -eq 0 ]; then
    # Remove temporary file
    rm -f "$TEMP_LIST"

    # Verzeichnis umbennnen wird beim naechctsne cron lauf uebersprungen
    NEW_NAME="$(dirname "$INPUT_DIR")/[CONVERTED] $DIR_NAME"
    mv "$INPUT_DIR" "$NEW_NAME"

    echo "✅ Fertig $OUTPUT_FILE"
else
    echo "❌ FFMpeg Fehler!!!"
fi

if [ -f "${INPUT_DIR}/${TEMPIMAGEFILE}" ]; then
   rm -f "${INPUT_DIR}/${TEMPIMAGEFILE}"
fi
Ergänzung ()

nutrix schrieb:
Ist das der ganze Code oben oder nur ein Teil des Codes?
Ergänzung ()


Noch genauer, set -vx, oder rufe das Script auf mit bash -vx Scriptname.

Interessiert Dich jetzt nur der Fehler oder auch Tipps zu Deinem Script?


vor allem erst mald er Fehler weil ich den super strange finde :D und wenn ich nicht weiss wann sich variablen in while schleifen ändern können ohne dass ich - so weit ich das sehe - die verändere das natürlich alles etwas hmm komplexer macht.....

Dann weiss ich ja nie was ändert sich da evtl sonst noch?

wenn ich den if Block "if [ "$VIDEO_PRESENT" = "video" ]; then.... auskommentiere dann verändert sich $file nicht - ist der drin verändert sich $file genau 1x in der Schleife eben wenn der if Block durchlaufen wird.

also es ändert sich nicht das aktuelle $file sondern das des nächsten Durchlaufs so wie wenn sich der Zeiger auf den Speicherbereich um ein Zeichen verschieben würde (denke bash nutzt intern NULL terminierte Strings ?) der übernächste und alle danach passen aber wieder.

Aber ich verstehe nicht wie der $file ändert

Der fix tut auch problemlos - aber hmmmmm wenn man nicht weiss wann und wieso man "fixen" muss das halt nicht so ideal.


Aber klar Verbesserungstipps sind natürlich auch immer super!
 
Zuletzt bearbeitet:
Wichtige Frage: wo läuft das Script unter welcher Umgebung genau bitte?

Als erstes würde ich mal alles immer über Dateien machen. Damit hast Du erst mal den Vorteil, daß Du den Output per find direkt nachvollziehen kannst.

Sprich, Du machst zuerst das Umlenken in eine Datei
Code:
find "$INPUT_DIR" -maxdepth 1 -type f -name "*.mp3" -print0 | sort -z >> $neue_Datei
und das dann in while read..done reinpacken.
Dann verstehe ich dieses Konstrukt nicht
Code:
while IFS= read -r -d '' file; do
Den IFS würde ich immer darüber global setzen, aber nicht direkt in der while Schleife, zudem für was?

Zudem kannst Du sowas hier
Code:
  # ersetze ' durch _ im Namen wegen ffmpeg
safe_file=$(echo "$file" | sed "s/['\"]/_/g")
durch Bash Inline Funktionen, dann sparst Du Dir einen Fork mit sed und es geht schneller:
Code:
 safe_file="${file//['\"]/_}"
Aber blöde gefragt, was hast Du da bitte für Dateinamen? Da darf doch gar kein "vorkommen? Und warum sind da ' drin? Sowas würde ich in Dateinamen immer absolut vermeiden.

Uzer1510 schrieb:
Aber ich verstehe nicht wie der $file ändert
Script-Sprachen haben kein so sauberes Variablenkonzept wie Programmiersprache mit diversen Übergabemechanismen (call by value/reference usw). Sprich, die Variablen laufen vermutlich in einem einfachen Stack. Das heißt, wenn Du Variablen z.B. in einer Schleife änderst, ist deren Zuordnung zu dieser Schleife und lokalen Gültigkeit nicht immer gegeben. Ich hatte in meinem langen Scriptleben genau 2x mal so einen Fall, daß Variablen ohne ersichtlichen Grund andere Werte lieferte als gedacht. Daher meine Frage, wo in welcher Umgebung Du das laufen hast. Es kann unter einem anderen Unix/Linux/WSL/Cygwin schon wieder ganz anders aussehen.

Daher ein genereller Tipp, paß einfach auf, wo Du welche Variable setzt und änderst, und trenne klar lokale Variablen in Schleifen von globalen Variablen.
 
Zuletzt bearbeitet:
Versuche mal mit ...
Code:
safe_file=$(realpath "$file")
und füge noch
Code:
echo "Original file: $file"
echo "Safe file: $safe_file"
hinzu.
 
  • Gefällt mir
Reaktionen: Uzer1510
nutrix schrieb:
Wichtige Frage: wo läuft das Script unter welcher Umgebung genau bitte?

Als erstes würde ich mal alles immer über Dateien machen. Damit hast Du erst mal den Vorteil, daß Du den Output per find direkt nachvollziehen kannst.

Sprich, Du machst zuerst das Umlenken in eine Datei
Code:
find "$INPUT_DIR" -maxdepth 1 -type f -name "*.mp3" -print0 | sort -z >> $neue_Datei
und das dann in while read..done reinpacken.
Dann verstehe ich dieses Konstrukt nicht
Code:
while IFS= read -r -d '' file; do
Den IFS würde ich immer darüber global setzen, aber nicht direkt in der while Schleife, zudem für was?
Naja ich setzte IFS= immer nur dann explizit "lokal" wenn ich das auch wirklich brauche und habe sonst immer das Standardverhalten.

if will halt für die externen Programme (oder wenn ich z.B. selbstgehäkelte bash function Blöcke aufrufe die ich per . einbinde) immer das Standard IFS sicher haben.

System ist ein normales debian 12 mit Linux 6.1.0-31-amd64 defaultkernel

Klar das kann ich sicher machen über einen pipe in einen "vorab" pipe in eine externe Datei aber letztendlich ist das auch dann nur ein "hotfix" mich würde aber interssieren waum das in dem einen (if-Zweig) Fall ein Zeichen verschwinden lässt? weil da evtl Auswirkung dann auf andere Schleifen haben könnte? Wenn man durch einen Array duchläuft evtl?
 
Uzer1510 schrieb:
Naja ich setzte IFS= immer nur dann explizit "lokal" wenn ich das auch wirklich brauche und habe sonst immer das Standardverhalten.
Hm, ich würde es an der Stelle rausnehmen. Sorry, ich hatte im obigen Beitrag noch einiges dazu gepackt. Wegen des undefinierten Stacks bei Variablen würde ich mal den IFS global setzen und beim while read rausnehmen.
 
  • Gefällt mir
Reaktionen: Uzer1510
Uzer1510 schrieb:
Naja ich setzte IFS= immer nur dann explizit "lokal" wenn ich das auch wirklich brauche und habe sonst immer das Standardverhalten.
Für deinen Fall nutze ich eher folgendes:
Code:
for i in  $(cat file)
do
echo $i
done
Macht meistens weniger Probleme als das Gefummel mit IFS.
 
  • Gefällt mir
Reaktionen: Uzer1510, stefan92x und nutrix
oicfar schrieb:
Versuche mal mit ...
Code:
safe_file=$(realpath "$file")
und füge noch
Code:
echo "Original file: $file"
echo "Safe file: $safe_file"
hinzu.


Das ist dann halt folgendes sobald er zur 2 . Datei kommt (01 enthält das Bild)

Code:
realpath: 'tank/mp3/#TOCONVERT_2_128CBR/test/02.mp3': Datei oder Verzeichnis nicht gefunden
Original file: tank/mp3/#TOCONVERT_2_128CBR/test/02.mp3

es fehlt halt dann das / am Anfang - wie gesagt nur bei dem einen Durchlauf nachdem er ein Bild extrahiert hat und immer nur das erste Zeichen

alle anderen sehen so aus
Code:
realpath: '/tank/mp3/#TOCONVERT_2_128CBR/test/01.mp3'
Original file: /tank/mp3/#TOCONVERT_2_128CBR/test/01.mp3

bis

Code:
realpath: '/tank/mp3/#TOCONVERT_2_128CBR/test/50.mp3'
Original file: /tank/mp3/#TOCONVERT_2_128CBR/test/50.mp3


wenn ich die Datei mit dem Bild umbennene in 33.mp3 dann fehlt das / bei der 34.mp3

Habe ich gar keine Datei mit einem Bild dann sind alle Pfade immer komplett vollständig.


---------------


IFS habe ich natürlich auch mal global getestet aber ist das identische Verhalten.

Mit geht es ja auch nicht daum dass man das fixen - das geht ja schon - sondern mich wundert einfach wieso das überhaupt auftritt?

weil das ja jetzt nicht irgendein superkomplexer Codeblock ist?
 
Zuletzt bearbeitet:
Wäre mal interessant, wie file und safe_file gleich zu Beginn der While-Schleife aussehen.

Und machst du die While-Schleife nicht unnötig kompliziert?
Ich würde es eigentlich so schreiben:

Code:
while read -r file; do
    echo "do stuff"
done < <(find "$INPUT_DIR" -maxdepth 1 -type f -iname "*.mp3" | sort)

Und die file-Variablen immer konsequent quoten, für den Fall, dass eine Datei ein Leerzeichen enthält.
 
  • Gefällt mir
Reaktionen: Uzer1510
die habe ich natürlich ganz oben als erstes in der while schleife gehabt :)
 
foofoobar schrieb:
Für deinen Fall nutze ich eher folgendes:
Code:
for i in  $(cat file)
do
echo $i
done
Macht meistens weniger Probleme als das Gefummel mit IFS.
Eine for-Schleife ist für Inhalte, die Leerzeichen enthalten können (wie Dateinamen) nicht praktikabel.
Die verwendete While-Schleife ist in vielen Fällen deutlich sicherer und sollte bevorzugt werden.
Ergänzung ()

Uzer1510 schrieb:
die habe ich natürlich ganz oben als erstes in der while schleife gehabt :)
Dann liegt es ja eher an dem find-Kommando, wenn schon zu Beginn der While-Schleife Teile vom Pfad fehlen.
Teste mal bitte mit meiner Form der While-Schleife.

Oh und rufe ffmpeg in Zeile 135 mal mit -nostdin auf.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Uzer1510 und nutrix
Die Namen schliessie ich halt aus denn wie gesagt wenn ich den if Zweig auskommentiere dann funktioniert es immer mit allen Dateien mit genau den gleichen Namen.

also der if Block Zeile 128 bis 142

Wären die Namen das Problem dann würden das Problem doch nicht dann komplett verschwinden?

Habe ich 128 bis 142 aktiviert dann muss ich bei den identischen Dateien bei den identischen Dateinamen nach dem Bild extrahieren einmal ein "/" ergänzen vorne - sonst muss ich da auch nichts machen auch dann sind die mp3s wieder vollständig verarbeitet.

Extrahiere ich kein Bild in 128 bis 142 funktioniert das Script IMMER ohne irgendwelche Fehler völlig egal welche Sonderzeichen in den Dateinamen sind (also ob Lerzeichen umlaute oder sonstwas) nur ' geht halt nicht aber das ersetze ich ja deshalb durch _

Die Dateinamen an sich schliesse ich halt deshalb sehr sicher aus.

Sonst würde das Auskommentieren von 128 bis 142 das Problem ja nicht fixen.

selbst wenn ich Zeile 135 auskommentiere tut alles mit allen Dateinamen
ist Zeile 135 drin dann fehlt nach der Ausführung beim nächsten $file das erste /


Hehe ich habe 135 mal geändert in

Code:
     unset IFS
             IFS=$' \t\n'
             export IFS=$' \t\n'
             ffmpeg -y -i "$safe_file" -map 0:v:0 -c copy "${INPUT_DIR}/${TEMPIMAGEFILE}"
             IFS=

Aber der Effekt ist der gleiche

Naja danke an alle dann werde ich halt einfach nachschauen ob der filename mit "/" beginnt und das dann nachbessern wenn das nach einem Bild rausziehen verlorenging beim nächsten Eintrag.
 
Zuletzt bearbeitet:
Uzer1510 schrieb:
selbst wenn ich Zeile 135 auskommentiere tut alles mit allen Dateinamen
ist Zeile 135 drin dann fehlt nach der Ausführung beim nächsten $file das erste /
??? Dann paßt doch schon was grundsätzlich nicht. Im Dateinamen sollten keine solchen Zeichen sein, wie kommt es dazu?
 
Versuche mit ...
Code:
#!/bin/bash

if [ "$#" -ne 2 ]; then
    echo "Idiot, das script braucht Parameter $0 <input_directory> <target_directory>"
    exit 1
fi

# Konvertiere die Verzeichnisse in absolute Pfade
INPUT_DIR="$(realpath "$1")"
TARGET_DIR="$(realpath "$2")"

# Entferne abschließende Slashes
INPUT_DIR="${INPUT_DIR%/}"
TARGET_DIR="${TARGET_DIR%/}"

TEMPIMAGEFILE="myEmbeddedImage.jpg"

check_if_running() {
    local script_name
    script_name="$(basename "$0")"

    local matching_pids
    echo "* Prüfe, ob das Skript bereits läuft..."

    matching_pids="$(pgrep -f "$script_name")"
    local count
    count="$(echo "$matching_pids" | wc -l)"

    if [[ "$count" -gt 1 ]] || ([[ "$count" -eq 1 ]] && [[ "$matching_pids" != "$$" ]]); then
        echo "Fehler: Das Skript läuft bereits."
        exit 1
    fi
}

echo ""
echo ""
echo ""
echo "-----------------------------------------------------------------------------"
echo "$0"
echo ""
echo "Quelle: $INPUT_DIR"
echo "Ziel: $TARGET_DIR"
echo "-----------------------------------------------------------------------------"

check_if_running

if [ ! -d "$INPUT_DIR" ]; then
    echo "Fehler: Quellverzeichnis '$INPUT_DIR' nicht vorhanden."
    exit 1
fi

mkdir -p "$TARGET_DIR"

# Ersetze ' und " im Verzeichnisnamen
SANITIZED_DIR="${INPUT_DIR//['\"]/_}"
if [ "$INPUT_DIR" != "$SANITIZED_DIR" ]; then
    mv "$INPUT_DIR" "$SANITIZED_DIR"
    INPUT_DIR="$SANITIZED_DIR"
    echo "* Quellverzeichnis umbenannt: $INPUT_DIR"
fi

DIR_NAME=$(basename "$INPUT_DIR")
OUTPUT_FILE="${TARGET_DIR}/${DIR_NAME}.mp3"
echo "* MP3-Zieldatei: $OUTPUT_FILE"
rm -f "$OUTPUT_FILE"

rm -f "${INPUT_DIR}/${TEMPIMAGEFILE}"

COVER_IMAGE=""

# Temporäre Datei für MP3-Liste
TEMP_LIST=$(mktemp)

# Überprüfen, ob alle Dateien bereits 128 CBR sind
ALL_128_CBR=true

while IFS= read -r -d '' file; do
    safe_file="$(realpath "$file")"

    # Ersetze ' und " im Dateinamen
    sanitized_file="${safe_file//['\"]/_}"
    if [ "$safe_file" != "$sanitized_file" ]; then
        mv "$safe_file" "$sanitized_file"
        safe_file="$sanitized_file"
    fi

    if $ALL_128_CBR; then
        # Prüfe Bitrate
        BITRATE=$(ffprobe -v error -select_streams a:0 -show_entries format=bit_rate -of default=noprint_wrappers=1:nokey=1 "$safe_file")
        BITRATE=$((BITRATE / 1000))
        VBR_DETECTED=$(ffprobe -v error -select_streams a:0 -show_entries format_tags=encoder -of default=noprint_wrappers=1:nokey=1 "$safe_file" | grep -i "VBR")

        # Falls eine Datei nicht 128 CBR ist, wird das Flag auf false gesetzt
        if [ "$BITRATE" -ne 128 ] || [ -n "$VBR_DETECTED" ]; then
            ALL_128_CBR=false
            echo "* Datei hat andere Bitrate (${BITRATE} kb/s): $(basename "$safe_file")"
        fi
    fi

    if [ ! -f "$safe_file" ]; then
        echo "Fehler: Datei nicht vorhanden: $safe_file"
        echo ""
        echo ""
        echo "ABBRUCH"
        echo ""
        echo ""
        exit 3
    fi

    echo "file '$safe_file'" >> "$TEMP_LIST"

    if [ -z "$COVER_IMAGE" ]; then
        VIDEO_PRESENT=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_type -of csv=p=0 "$safe_file")

        if [ "$VIDEO_PRESENT" = "video" ] && [ ! -f "${INPUT_DIR}/${TEMPIMAGEFILE}" ]; then
            ffmpeg -y -i "$safe_file" -map 0:v:0 -c copy "${INPUT_DIR}/${TEMPIMAGEFILE}"
            if [ -f "${INPUT_DIR}/${TEMPIMAGEFILE}" ]; then
                COVER_IMAGE="${INPUT_DIR}/${TEMPIMAGEFILE}"
                echo "* Coverbild extrahiert und wird verwendet."
            fi
        fi
    fi
done < <(find "$INPUT_DIR" -maxdepth 1 -type f -name "*.mp3" -print0 | sort -z)

# Überprüfen, ob TEMP_LIST leer ist
if [ ! -s "$TEMP_LIST" ]; then
    echo "Fehler: Keine MP3-Dateien gefunden."
    rm -f "$TEMP_LIST"
    exit 1
fi

# Falls kein Coverbild extrahiert wurde, versuche eines im Verzeichnis zu finden
if [ -z "$COVER_IMAGE" ]; then
    COVER_IMAGE=$(find "$INPUT_DIR" -maxdepth 1 -type f -iname "*.jpg" | head -n 1)
    if [ -n "$COVER_IMAGE" ]; then
        echo "* Verwende gefundenes Coverbild: $(basename "$COVER_IMAGE")"
    fi
fi

echo "Starte ffmpeg..."
echo ""

# Falls alle MP3s 128 CBR haben, nur zusammenfügen
if $ALL_128_CBR; then
    echo "✅ Keine Neucodierung notwendig..."
    if [ -n "$COVER_IMAGE" ]; then
        ffmpeg -hide_banner -f concat -safe 0 -i "$TEMP_LIST" -i "$COVER_IMAGE" -map 0:a -map 1 -c copy -disposition:v attached_pic \
               -id3v2_version 3 -metadata:s:v title="Album cover" -metadata:s:v comment="Cover (front)" -y "$OUTPUT_FILE"
    else
        ffmpeg -hide_banner -f concat -safe 0 -i "$TEMP_LIST" -c copy -y "$OUTPUT_FILE"
    fi
else
    echo "⚠️ Mindestens eine Datei ist nicht 128 CBR - Neucodierung erforderlich..."
    if [ -n "$COVER_IMAGE" ]; then
        ffmpeg -hide_banner -f concat -safe 0 -i "$TEMP_LIST" \
               -i "$COVER_IMAGE" \
               -map 0:a -map 1 \
               -c:a libmp3lame -b:a 128k \
               -c:v copy \
               -disposition:v attached_pic \
               -metadata:s:v title="Album cover" \
               -metadata:s:v comment="Cover (front)" \
               -id3v2_version 3 \
               -write_id3v1 1 \
               -threads 0 \
               -y "$OUTPUT_FILE"
    else
        ffmpeg -hide_banner -f concat -safe 0 -i "$TEMP_LIST" -acodec libmp3lame -b:a 128k -id3v2_version 3 -write_id3v1 1 -y -threads 0 "$OUTPUT_FILE"
    fi
fi

# Erfolgsmeldung
if [ $? -eq 0 ]; then
    rm -f "$TEMP_LIST"
    NEW_NAME="$(dirname "$INPUT_DIR")/[CONVERTED] $DIR_NAME"
    mv "$INPUT_DIR" "$NEW_NAME"
    echo "✅ Fertig: $OUTPUT_FILE"
else
    echo "❌ Fehler beim Verarbeiten mit ffmpeg!"
fi

# Aufräumen
rm -f "${INPUT_DIR}/${TEMPIMAGEFILE}"
Bin nicht sicher, ob das alles geht. D.h. extra 2-3 Dateien zum Testen nehmen. Habe hier keine Möglichkeit es zu testen.

Führe das mit bash -vx <...> aus. Sollte es Probleme geben, schicke mal die Ausgabe.
 
@Uzer1510
Okay, hast recht.
Dann füge dem ffmpeg-Aufruf in Zeile 135 die Option '-nostdin' hinzu. Das sollte das Problem lösen.
 
  • Gefällt mir
Reaktionen: Uzer1510
@R00kie Ein weiterer Nervfaktor bei diesen while/read Schleifen:
Code:
$ while read f; do echo $f; done < list
a
b
c d
$ while read f; do cat > /dev/null; echo $f; done < list
a
$
 
Zurück
Oben