Einfügen (Diashow)

Januar 2017
Diashows, die Auswahl eines Bildes aus mehreren, und Ähnliches kommt in Webanwendungen recht häufig vor. Dabei könnten alle Bilder direkt in der Webseite eingebettet sein, meistens jedoch liegen sie auf der Serverseite und das vom Nutzer ausgewählte Bild wird vom Server heruntergeladen.
Auf der Serverseite liegen die Bilder üblicherweise in einem bestimmten Ordner (Folder, Directory) und die Dateinamen der Bilder haben ein bestimmtes Muster, das die Auswahl vereinfacht. Das Muster besteht aus einem immer gleichem Teil, z.B. Foto, einem Zahlenanteil, z. B. 01, 02, usw. und der Dateiendung, z.B. .jpg.
Ein solches Szenario war im vorliegenden Fall zutreffend. Auf der Serverseite werkelte ein Apache unter Linux. Und so zeigte ls die Bilder an; Option -1 sorgt für zeilenweise Darstellung:
$ ls -1
Foto01.jpg
Foto02.jpg
Foto03.jpg
Foto04.jpg
Foto05.jpg
Foto06.jpg
Foto07.jpg
Foto08.jpg

Das Problem

Der Zahlenanteil musste im vorliegenden Fall eine zweistellige, fortlaufende Nummer sein. Soll nun z.B. an die 4. Stelle ein neues Bild eingefügt werden, dann müssen zunächst alle Bilder ab dieser Stelle umbenannt werden (Foto04.jpg in Foto05.jpg, Foto05.jpg in Foto06.jpg, usw.).
Wird die Bildmenge von einem Tool (CMS o.ä.) generiert, dann sollte das Einfügen darüber kein Problem sein. Diese Möglichkeit stand nicht zur Verfügung.
Damit die bestehenden Bilder nicht versehentlich über kopiert werden, muss das Umbenennen von hinten beginnen also im vorliegenden Fall Foto08.jpg in Foto09.jpg zuerst.
Bei einer so kleinen Bildmenge kann man das durch manuelles Eingeben von Kopierkommandos lösen (Kommando mv). Ist die Liste sehr lang, sollte man ein Shellscript schreiben.

Gelöst mit traditionellen Mitteln

Das folgende Script arbeitet mit traditionellen Ausdrücken, wie sie schon in der Bourne Shell bekannt waren.
Wir brauchen eine Schleife, die nacheinander die Kopiervorgänge in definierter Reihenfolge abarbeitet. Das könnte man mit der for-Schleife machen; erster Ansatz:
LISTE='8 7 6 5 4'
for i in $LISTE
do
  ...Kopiervorgang...
done
Die Schleife weist der Variablen i bei jedem Durchlauf den nächsten Wert aus der Liste zu.
Nun sollten aber einstellige Zahlen zweistellig mit führender Null dargestellt werden. Zwar könnte man das in der Liste gleich so notieren (also '08 07 06 ...'), mit dem Kommando printf kann man einfach umwandeln.
IDX=$(printf '%02u' $i)
In der Variablen IDX wird eine einstellige ganze Zahl zweistellig mit führender Null hinterlegt, mehrstellige Zahlen bleiben unverändert.
Außer der aktuellen Zahl braucht man die nächstfolgende ganze Zahl, die erhält durch Addition mit 1. Zu beachten: Jeder Ausdruck, also auch eine Zahl, ist auf Shellebene immer eine Zeichenkette (String). Das Kommando echo 3 + 1 liefert daher niemals 4. Wir brauchen ein Kommando, das Zahlen als solche erkennt; das oben verwendete printf kann es.
Zum Rechnen nehmen wir das Kommando expr:
NEXT=$(expr $i + 1)
Jetzt enthält NEXT zwar den nächsthöheren Wert, aber um die Zweistelligkeit müssen wir uns trotzdem kümmern:
NIX=$(printf '%02u' $NEXT)
Zu guter Letzt erzeugen wir die Dateinamen im benötigten Muster
filealt="Foto$IDX.jpg"
fileneu="Foto$NIX.jpg"
und könnten nun das Umbenennen programmieren:
echo "Benenne $filealt in $fileneu um"
# mv $filealt $fileneu
Wie man sieht, ist die Zeile mit dem Kommando mv auskommentiert. Dafür gibt es zuvor eine echo-Zeile, die die in der zweiten Zeile vorkommenden Variablen verwendet. Lässt man das Script jetzt laufen, kann nichts passieren, aber die echo-Ausgaben zeigen, ob das Script funktionieren würde.
$ ./shiftfotos.sh
Benenne Foto08.jpg in Foto09.jpg um
Benenne Foto07.jpg in Foto08.jpg um
Benenne Foto06.jpg in Foto07.jpg um
Benenne Foto05.jpg in Foto06.jpg um
Benenne Foto04.jpg in Foto05.jpg um
Solche oder andere Test werden dringend empfohlen, bevor man das Script "scharf" schaltet.
Der Scriptname war shiftfotos.sh. Hat man sich also von der Funktionstüchtigkeit überzeugt, kann man das Kommentarzeichen vor mv entfernen und das Script erneut auf die Bilddateien loslassen.
Ein Sichern der Bilder vorher kann aber nie schaden!

Das Script komplett

#
# shiftfotos.sh
#

LISTE='8 7 6 5 4'

for i in $LISTE
do

NEXT=$(expr $i + 1)
IDX=$(printf '%02u' $i)
NIX=$(printf '%02u' $NEXT)
file1="Foto$IDX.jpg"
file2="Foto$NIX.jpg"

echo "Benenne $file1 in $file2 um"
# mv $file1 $file2

done

Update mit moderneren Mitteln

Schleifenwerte

Das Notieren der Schleifenwerte in LISTE ist nicht gerade prickelnd, und außerdem bei vielen Bildern doch recht mühselig.
Hier hilft das externe Kommando seq weiter. Es wurde entwickelt, um eben Zahlenlisten zu generieren.
LIST=$(seq --separator=' ' 8 -1 4)
# Prinzip: seq [Optionen] Anfangswert Inkrement Endwert
Nun muss man nur noch drei Werte statt einer Liste notieren, und das ist natürlich wesentlich günstiger. seq verwendet als Trennzeichen den Zeilenwechsel, mithilfe der Option --separator wurde Leerzeichen eingestellt.

Berechnungen

Anstelle mit dem externen Kommando expr zu addieren, kann man den arithmetischen Operator $((Ausdruck)) der Shell (bash) verwenden.
NEXT=$(($i + 1))

Das komplette Script

#
# shiftfotos.sh
#

LIST=$(seq --separator=' ' 8 -1 4)

for i in $LIST
do

NEXT=$(($i + 1))
IDX=$(printf '%02u' $i)
NIX=$(printf '%02u' $NEXT)
file1="Foto$IDX.jpg"
file2="Foto$NIX.jpg"

echo "Benenne $file1 in $file2 um"
# mv $file1 $file2

done

Noch ein Update

Eine andere for-Schleife

Die bash kennt eine andere Form der for-Schleife, die direkt numerische Ausdrücke versteht.
# Prinzip: for ((Startwert zuweisen; Endetest; nächsten Wert berechnen))
for ((i=8; $i>4; i=$i-1))
do
 ...
done 

Das komplette Script

#
# shiftfotos.sh
#

for ((i=8; $i>4; i=$i-1))
do

NEXT=$(($i + 1))
IDX=$(printf '%02u' $i)
NIX=$(printf '%02u' $NEXT)
file1="Foto$IDX.jpg"
file2="Foto$NIX.jpg"

echo "Benenne $file1 in $file2 um"
# mv $file1 $file2

done
Und bestimmt kann man noch mehr verbessern.