staging.inyokaproject.org

Bash-Skript: Meldung "Mehrdeutige Umlenkung"

Status: Ungelöst | Ubuntu-Version: Ubuntu 24.04 (Noble Numbat)
Antworten |

Benni11

Anmeldungsdatum:
14. April 2009

Beiträge: 201

Hallo Experten, googeln war mit meinen bescheidenen Englischkenntnissen nicht recht ergiebig, das Wiki für Anfänger im Bash-Skripting lässt sich hierüber nicht aus, deshalb hier mein Problem:

Das Skript soll in ausgewählten Verzeichnissen den Namen und das Datum der jeweils jüngsten Dateien ermitteln, um den Abgleich zweier Laufwerke zu ermöglichen; das Programm meld streikt bei den vorgegebenen Verzeichnisumfängen.

Der Plan: Das mit find ermittelte jeweilige Datum und der Dateiname landen im Verzeichnis /media/DATEN/Abgleich/ in jeweils einer eigenen Textdatei. Am Ende des Laufwerkabgleichs sollen die Dateistände des ersten Laufwerks ("Quelle") mit den Ständen des zweiten Laufwerks ("Ziel") - per cut auf das erforderliche Maß gekürzt - mit Hilfe der Textdatei Kontrolle gegenübergestellt werden: Quelle: Verzeichnis1/Datum & Dateiname vs Ziel: Verzeichnis1/Datum & Dateiname.

Obwohl die jeweilige Variable nur einmalig beschickt werden soll, kommt die Meldung "Mehrdeutige Umlenkung" und die Variable bleibt leer.

Auszug aus dem Skript:

#!/bin/sh
# chmod +x ~/bin/*.sh  # Skript ausführbar machen
~$ touch /media/DATEN/Abgleich/Kontrolle.txt 
~$ set Kontrolle=/media/DATEN/Abgleich/Kontrolle.txt 
~$ touch /media/DATEN/Abgleich/2_Zwi-sicher_Q.txt 
~$ set Zq=/media/DATEN/Abgleich/2_Zwi-sicher_Q.txt # Quelldatei lange Ausgabe
~$ touch /media/DATEN/Abgleich/2_Zwi-sicher_Q-kurz.txt && set Zq1=media/DATEN/8_Abgleich/2_Zwi-sicher_Q-kurz.txt  # Quelldatei kurze Ausgabe
~$ find /media/DATEN/2_Zwi-Sicher/ -type f -printf '%T+ %p\n' | sort | tail -n1 > $Zq
bash: $Zq: Mehrdeutige Umlenkung
~$ Zq1=$(cut -b 1-10,47-140 $Zq)  # keine Reaktion, nach Abbruch mit STRG+C nachfolgende Ausgabe:
Cbash: $Kontrolle: Mehrdeutige Umlenkung 

Worin besteht die mehrdeutige Umlenkung sowohl in Bezug auf die Variable als auch in Bezug auf die Datei Kontrolle.txt und wie kann ich Skript-Anfänger dies vermeiden? Schon jetzt vielen Dank fürs Interesse.

Gruß Benni11

TK87

Anmeldungsdatum:
8. Juli 2019

Beiträge: 266

Moin,

Benni11 schrieb:

~$ set Kontrolle=/media/DATEN/Abgleich/Kontrolle.txt 
~$ set Zq=/media/DATEN/Abgleich/2_Zwi-sicher_Q.txt # Quelldatei lange Ausgabe

Variablen werden bei sh nicht mit set deklariert, daher bleibt die Variablen schlicht leer und die Shell versteht nicht wohin du umleiten willst.

Entweder mit declare, oder einfach nur...

1
2
Kontrolle=/media/DATEN/Abgleich/Kontrolle.txt
Zq=/media/DATEN/Abgleich/2_Zwi-sicher_Q.txt # Quelldatei lange Ausgabe

dann funktioniert es auch.

BTW: Nimm besser bash statt sh, da hast du ein paar mehr Möglichkeiten (z.B. Arrays).

Gruß Thomas

Ruth-Wies

Avatar von Ruth-Wies

Anmeldungsdatum:
12. April 2023

Beiträge: 450

Benni11 schrieb:

… das Wiki für Anfänger im Bash-Skripting …

Hast du nicht beherzigt, denn dort steht nirgends, dass man Variablen mit set definiert. (Wie TK87 auch schon schrieb.)

Was set macht, kannst z. B. hier nachlesen: https://openbook.rheinwerk-verlag.de/shell_programmierung/shell_005_006.htm

Auszug aus dem Skript:

Äh? Da ist kein Skript. Das ist eine Mischung aus Prompt, Kommando und Ausgabe; Also ein Terminalmitschnitt. In einem Skript stehen nur Kommandos und alles andere allenfalls als Kommentar.

~$ touch /media/DATEN/Abgleich/2_Zwi-sicher_Q-kurz.txt && set Zq1=media/DATEN/8_Abgleich/2_Zwi-sicher_Q-kurz.txt  # Quelldatei kurze Ausgabe

Und Tippfehler vermeiden. Zq1 entspräche hier nicht der angelegten Datei. 😉 (Macht in deinem Auszug keinen Unterschied, da Zq1 nicht verwendet, sondern neu zugewiesen wird. Wenn du hier nichts ausgelassen hast, dann ist diese Zuordnung also überflüssig.)

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

@Benni11: Was macht das denn für einen Sinn nachdem man einen Dateinamen benutzt, den an einen Variablennamen zu binden. Das würde man doch eher umgekehrt machen, den Dateinamen an einen Namen binden, und dann den Namen im touch verwenden. Damit man den nur einmal tatsächlich schreiben muss, und Tippfehler beim ersten schreiben sowie bei Änderungen zu vermeiden. Das Muster wiederholt sich ja. Und da ist ja sogar schon ein Fehler denn nach dem touch mit dem && wird $Zq1 an einen anderen Dateinamen gebunden als dem der beim touch steht. Das soll ja wahrscheinlich nicht so sein. Es wäre an der Stelle vielleicht sinnvoll den immer wiederkehrenden Teilpfad auch nicht immer wieder hin zu schreiben, sondern an einen Namen zu binden.

Wobei das mit dem &&-Test nicht wirklich Sinn macht. Wenn touch nicht funktioniert, wird die Variablen nicht definiert, aber es wird einfach weiter gemacht als wäre alles in Ordnung. Das wird ja spätestens wenn der nicht definierte Namen verwendet wird, zu einem Folgeproblem führen.

Namen sollten keine kryptischen Abkürzungen enthalten oder sogar nur daraus bestehen. Das $Zq ein Dateiname und $Zq1 etwas aus der ersten Zeile einer Datei ausgeschnittenes ist, kann man ja nicht mal ansatzweise erraten.

Die magischen Zahlen bei cut sollte man mindestens in einem Kommentar erklären, die beim Dateinamen am besten auch berechnen, denn da wurde ja anscheinend per Hand ausgerechnet oder abgezählt wie lang der Präfix ist, der da über übersprungen werden muss. Das ist nicht wirklich robust gegen Änderungen. Wie kommt denn die 140 zustande?

Muss das mit den Dateien als Zwischenspeicher denn überhaupt sein? cut auf einer Zeile kann man auch mit Bash-Bordmitteln machen.

1
2
3
4
# Zeitstempel und Dateipfad der jüngst geänderten Datei.
Result=$(find /media/DATEN/2_Zwi-Sicher/ -type f -printf '%T+ %p\0' | sort -z | tail -z -n 1 | head -c -1)
# Datumsangabe und Teil (?) des Pfades ausschneiden.
Result="${Result:0:10} ${Result:47}"

Auch hier ist die 47 erklärungsbedürftig und zu berechnen.

Benni11

(Themenstarter)

Anmeldungsdatum:
14. April 2009

Beiträge: 201

Ich war unterwegs, deshalb erst jetzt meine Reaktion

@ TK87: vielen Dank für deinen Tipp. Ich hatte es ursprünglich ohne set versucht, aber ebenfalls die Meldungen "mehrdeutige Umlenkung" erhalten.

@ Ruth-Wies: dir ebenfalls vielen Dank für deine Anmerkungen. Ich werde künftig den Unterschied zwischen Begriffen Terminalmitschnitt und Skript beachten; für den Lapsus mit Zq1 bitte ich um Entschuldigung, hätte ich beim Drüberlesen erkennen können.

@ Marc_BlackJack_Rintsch: dir danke ich ebenfalls. Ich habe aus lange zurückliegender beruflicher Zeit mit Windwos und Excel den Mut zum Experimentieren und sehr, sehr rudfimentäre Erkenntnisse aus dem Abfassen von Makros und Batch-Dateien ins Privatleben gerettet. Mit deiner Lösung beginnt für mich als wirklichen Anfänger die Hohe Schule des Skriptings. Mein Ansatz: die vielen gefundenen Ergebnisse für die nachfolgende Bearbeitung / Verwendung in Textdateien zur späteren Weitervereinbarung abspeichern. Um nicht jeweils den Pfad zum Ablageort eingeben zu müssen, habe ich die Variablen als Platzhalter festgelegt (in der Langfassung des Skripts selbst sind als Gedächtnisstützen Erläuterungen zu den Platzhaltern und cut enthalten).

Du empfiehlst statt des Umwegs über eine "Sammeldatei" den kurzen Weg, ich werde mein Skript insoweit umschreiben.

Wie ohne Abzählen die Länge der Textschnipsel für die Variablen zum Datenabgleich sonst noch ermitteln werden können, ist mir als Anfänger allerdings nicht bekannt. Die bei cut verwendete Zahl 140 enthält noch einen Puffer für etwaige neue Unterverzeichnisse, cut meckert nicht und gibt nur die wahre Länge des Dateinamens an.

Ich setze das Thema auf gelöst.

Es grüßt Benni11

Ruth-Wies

Avatar von Ruth-Wies

Anmeldungsdatum:
12. April 2023

Beiträge: 450

Du brauchst dich nicht zu entschuldigen. Fehler sind da um gemacht zu werden. Du glaubst nicht, wie ich an manchen Tagen über meine eigenen verzweifel. 😉

Benni11 schrieb:

… Die bei cut verwendete Zahl 140 enthält noch einen Puffer für etwaige neue Unterverzeichnisse, …

Die Sache mit dem cut war mir auch aufgefallen, aber ich wollte ich dich eigentlich machen lassen. Du kannst es auch ohne Zählen hinbekommen, in dem du die letzte Zahl einfach weglässt.

cut schreibt:

Positionsangaben müssen nicht durch vorbestimmte Endpunkte bestimmt sein:

echo "123456789" | cut -c 5- 
56789

Mich würde eher der nahtlose Übergang zwischen Zeitstempel und Dateinamen stören, aber für einen Vergleich durch die Maschine ist das Wurscht.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

@Benni11: Wie kommt denn die Startzahl beim cut im zweiten Bereich zustande? Da wird ja ein Teil des Pfades übersprungen und diesen Teil sollte man halt nicht abzählen sondern im Skript berechnen, weil man sonst Probleme bekommt wenn sich dieser Teil den man überspringen will, mal ändert. Dann muss man neu abzählen. Daran muss man denken und man kann sich verzählen.

Und warum wird die nur die Jahreszahl ausgeschnitten? Sollen Verzeichnisse als gleich gelten solange die jüngste Datei im gleichen Jahr zuletzt verändert wurde, auch wenn die Zeitstempel ansonsten nicht gleich sind?

Benni11

(Themenstarter)

Anmeldungsdatum:
14. April 2009

Beiträge: 201

@Ruth-Wies und @Marc_BlackJack_Rintsch. Danke an euch beide für die weitergehende Hilfe, ich habe deshalb das Thema wieder auf ungelöst gestellt.

@Ruth-Wies: mit Marcs Ansatz besteht ein Leerzeichen zwischen Datum und Dateinamen, bei meiner umständlichen Lösung müsste ich noch mit cut Feinpflege betreiben.

~$ Result=$(find /media/DATEN/2_Zwi-Sicher/ -type f -printf '%T+ %p\0' | sort -z | tail -z -n 1 | head -c -1)
~$ Result="${Result:0:10} ${Result:43:100}"
~$ echo "Quelldatei: $Result"
Quelldatei: 2025-09-09 /2_Zwi-Sicher/Banken_Hibiscus-ff/.jameica/jameica.log 

@Marc_BlackJack_Rintsch: Deine Lösung läuft prima und macht meine Umwege überflüssig.

Kürzen der Pfadausgabe auf notwendige Textschnipsel: bis jetzt funktioniert dies nur durch Abzählen oder mit calc. Als Lösung innerhalb des Skripts (angedacht, aber noch nicht versucht): künftig nur Datum und Dateinamen verwenden, mit grep oder anderem geeigneten Werkzeug den letzten Slash im Textstring suchen und so den Beginn des Dateinamens bestimmen - ich hoffe, es gelingt.

Gewünschte Datumsangabe ist DD-MM-YYYY (wie bei deiner Lösung).

Es dankt und grüßt Benni11

Antworten |