ubuntuusers.de

String-Vergleich im Bash-Script

Status: Gelöst | Ubuntu-Version: Ubuntu GNOME 14.04 (Trusty Tahr)
Antworten |

alex9050

Anmeldungsdatum:
28. Juni 2014

Beiträge: 11

Hallo,

hat jemand einen Lösungsansatz für folgendes Problem?: In einem Verzeichnis befinden sich eine beliebige Anzahl Dateien. Die Dateinamen folgen dem Muster

1
3043289-ghjt-hgts-sonquatsch-undsoweiter....txt

Die Nummerierung am Anfang des Dateinamens ist aufsteigend, aber nicht durchgehend. In einer Datei wurde der Dateiname mit der höchsten Nummer gespeichert.

Im Script sollen nun nur die Dateien berücksichtigt werden, deren Nummer größer ist als die, welche in besagter Datei gespeichert wurde. Ich habe da etwas mit test versucht, eigentlich war mir schon klar, daß es nicht funktionieren würde, da die Option ja für Zahlen gedacht ist, aber: Versuch macht klug 🙄

1
2
3
4
5
6
7
for artikel in "$outputdir/"*.txt ; do

	if [ "$artikel" -gt "./letzter_artikel" ]
	then echo $(basename  $artikel) >> "./newssort.tmp"
	fi

done

Ich hab's auch nur reingestellt, um das Problem zu veranschaulichen.

Eigentlich wäre es ja auch nur nötig, den nummerischen Anteil zu vergleichen. Gibt es eine entsprechende Funtion wie bspw. "VAL" in Basic?

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Du könntest den numerischen Teil einfach mit Hilfe von zwei Parameter-Expansionen herausklamüsern, nur mit den Mitteln der Shell:

1
2
3
4
5
6
7
8
9
for artikelpfad in "$outputdir/"*.txt ; do
	artikel="${artikelpfad##/*}"
	artikelnr=${artikel%%*-}
	if [ $artikelnr -gt $letzte_artikelnr ]; then
		letzte_artikelnr=$artikelnr			# innerhalb der Schleife: nur merken
		letzter_artikel=$artikel
	fi
done
echo "$letzter_artikel"  >>  "newssort.tmp"			# schreiben erst am Schluß, hinter der Schleife

Das setzt voraus, dass nach den Ziffern immer der "-" kommt.
Wenn Du ausdrücklich nur die Ziffern am Anfang haben willst, egal was danach kommt, kannst Du eine Muster-Ersetzung nehmen:
artikelnr=${artikel/[^0-9]*/} (... die Doku dazu steht im Bash- Manual)

LG,

track

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13192

Du brauchst zwei Dinge:

  1. Musst Du nicht den Dateinamen der höchsten Zahl sondern den Inhalt der Datei vergleichen.

  2. Solltest Du den numerischen Teil aus dem Dateinamen extrahieren für den Vergleich.

  3. Der echo bei basename ist überflüssig.

Also etwa so

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
max_file="./letzter_artikel"

if [ -r "$max_file" ]; then
  max=$(cat "$max_file")
else
  max=0
fi

for artikel in "$outputdir/"*.txt; do
  base_name="${artikel##*/}"
  num="${base_name%%-*}"

  echo "$num" # debug

  if [ $num -gt $max ]; then
    echo "$base_name" >> "newssort.tmp"
    max=$num
  fi
done

echo "$max" >| "$max_file"

track Du änderst da aber die Semantik, weil Du nur einen Artikel nach der Schleife schreibst. Ob das das ist, was OP wollte, weiß ich nicht. Ich war davon ausgegangen, dass er jeden neuen Artikel listen will.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17608

Wohnort: Berlin

alex9050 schrieb:

In einem Verzeichnis befinden sich eine beliebige Anzahl Dateien. Die Dateinamen folgen dem Muster

1
3043289-ghjt-hgts-sonquatsch-undsoweiter....txt

Das ist ein Beispiel und daher nur ein Muster für sich selbst. Besteht der Name nur aus Ziffern, Buchstaben, Punkten und Dashes? Keine Blanks und ähnliches?

Die Nummerierung am Anfang des Dateinamens ist aufsteigend, aber nicht durchgehend.

30 ist absteigend, 432 ist absteigend - Du meinst die Nummerierung der Dateien geschieht aufsteigend?

In einer Datei wurde der Dateiname mit der höchsten Nummer gespeichert.

Im Script sollen nun nur die Dateien berücksichtigt werden, deren Nummer größer ist als die, welche in besagter Datei gespeichert wurde.

Das kann ja keine sein, weil Du sagtest, dass der Name mit der höchsten Nummer gespeichert wurde. Es ist also die ehemals höchste Nummer.

1
2
3
4
5
for artikel in "$outputdir/"*.txt ; do
	if [ "$artikel" -gt "./letzter_artikel" ]
	then echo $(basename  $artikel) >> "./newssort.tmp"
	fi
done

Outputdir wurde nicht vorgestellt. Sieht so aus, als handle es sich für uns um ein Inputdir. "./letzter_artikel" soll eine Name, der mit einer Nummer startet sein?

1
2
3
4
5
6
7
8
9
# letzter_artikel sei die Datei, die die Zahl (oder den ganzen Dateinamen) enthält.
max=$(<"letzter_artikel")
# Annahme: Es sind sonst keine .txt-Dateien im Verzeichnis
ls *.txt | sort -n > sorted.list
# Von max-.* (falls max nur die Nummer ist, sonst $max/ ohne -.* benutzen)
sed -n "/$max-.*/,/$$/p" sorted.list | sed '1d' 
# bis(:= /,/) $$=Dateiende alles lesen, nicht per default ausgeben (-n) 
# sondern nur die Zeilen von /VON/,/BIS/p (print). 
# Dann Zeile 1d - delete, denn das Kommando zuvor wirkt inklusive.

alex9050

(Themenstarter)

Anmeldungsdatum:
28. Juni 2014

Beiträge: 11

Ich danke euch Dreien, track, rklm und user_unknown für Eure Mühe.

Ich habe mit letztlich für den Vorschlag von rklm entschieden, weil ich den verstehen kann. Ich bin ziemlicher Newbie, was Scripting betrifft. Ich will damit nicht sagen, daß die Vorschläge von track und user_unknown nicht auch funktionieren. Ich habe sie mir kopiert und werde mich damit auseinandersetzen. Wenn ich die auch verstehe, bin ich bestimmt ein wenig weiter.

@user_unknown Ich war vielleicht ein wenig knapp in der Beschreibung des Problems, wollte mich aber auf den Teil des Projektes beschränken, der das eigentliche Problem enthält (der Rest ist gelöst):

In einem gegebenen Verzeichnis (inputdir) befindet sich eine Anzahl Artikel, die tgl. aktualisiert wird.

Diese werden nach der Aktualisierung von html nach text konvertiert und nach outputdir geschrieben (daher "./outputdir)

Die Dateinamen enthalten eine aufsteigende Nummerierung am Ende (nach dem reinen Text-Teil: "ich-gehe-heute-ins-schwimmbad-302844.html" beispielsweise).

Nun wird der Datei-Name geändert, um die Nummer an den Anfang zu bekommen, und damit eine vernünftige Sortierung möglich wird: "302844-ich-gehe-heute-ins-schwimmbad.txt"

Jetzt kam das eigentliche Problem in's Spiel: wie verhindere ich, daß ich alte, bereits bearbeitete Dateien immer wieder mitbekomme. Mein Gedanke war: den Dateinamen der Datei, welche beim letzten Lauf zuletzt bearbeitet wurde in eine Datei speichern und beim nächsten Lauf vergleichen. Einfach die Dateien im inputdir vor der Aktualisierung löschen, geht nicht, weil bei der Aktualisierung auch wieder alte Dateien anfallen.

Das Einzige was nun noch bleibt, ist mailx zu erziehen 😠 aber das gehört wohl nicht mehr hierher (falsches thema)

Nochmal vielen Dank an alle

Antworten |