staging.inyokaproject.org

Bash 4 - Numerische Variablengenerierung im Skript aus Variablen

Status: Ungelöst | Ubuntu-Version: Kein Ubuntu
Antworten |

Rava77

Anmeldungsdatum:
17. Dezember 2018

Beiträge: Zähle...

Hallo,

aufbauend auf Info von hier https://forum.ubuntuusers.de/topic/bash-variablengenerierung-mit-fuehrenden-nulle/ möchte ich ein flexibles Downloadscript schreiben, dem ich die "von" und "bis" Werte per Parameter übergeben kann. Bisher befindet es sich in der Testphase, da habe ich die Parameter per z.B. "declare -i startk=99" definiert. Das soll dann am Ende z.B. so verwendet werden: declare -i startk=$1

Leider klappt da was nicht. Das Skript soll am Ende etwa aussehen, nur eben das es auch funktionieren soll wie gedacht. In der Testphase ist das "wget" noch durch ein "echo wget" ersetzt

1
2
3
4
5
6
7
8
#!/bin/bash
echo Start of $0
declare -i startk=99
declare -i endk=111
namestart=https://static.example.com/path/filename 
nameend=.jpg
for i in {$startk..$endk}; do k="$(printf '%03d' "$i")"; echo wget $namestart$k$nameend; done
echo End of $0

Das gibt folgenden Fehler:

1
2
3
4
5
$ ./download-dummytest.sh 
Start of ./download-dummytest.sh
./download-dummytest.sh: line 8: printf: {99..111}: invalid number
wget https://static.example.com/path/filename000.jpg
End of ./download-dummytest.sh

In einer Schleife mit "{n1..n2}" kann man zumindest so die Zahlen n1 und n2 wohl nicht durch Variablen ersetzten.

Wenn ich das ganze so programmiere

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash
echo Start of $0
#declare -i startk=99
#declare -i endk=111
namestart=https://static.example.com/path/filename
nameend=.jpg

for i in {99..111}; do k="$(printf '%03d' "$i")"; echo wget $namestart$k$nameend; done

echo End of $0

macht das Skript das was es soll, ich müßte dann aber für jeden Aufruf das Script ändern, anstatt die Variablen an das Skript zu übergeben. (Die Variablen $namestart und $nameend werden am Ende dann auch als Variablen an das Skript übergeben.)

Die letzte Variante sieht dann in der Exekution so aus:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
./download-dummytest.sh 
Start of ./download-dummytest.sh
wget https://static.example.com/path/filename099.jpg
wget https://static.example.com/path/filename100.jpg
wget https://static.example.com/path/filename101.jpg
wget https://static.example.com/path/filename102.jpg
wget https://static.example.com/path/filename103.jpg
wget https://static.example.com/path/filename104.jpg
wget https://static.example.com/path/filename105.jpg
wget https://static.example.com/path/filename106.jpg
wget https://static.example.com/path/filename107.jpg
wget https://static.example.com/path/filename108.jpg
wget https://static.example.com/path/filename109.jpg
wget https://static.example.com/path/filename110.jpg
wget https://static.example.com/path/filename111.jpg
End of ./download-dummytest.sh

Das Problem also, wie kann ich per for i in {$startk..$endk} und k="$(printf '%03d' "$i")" eine Schleife erzeugen, welche die Von und Bis Zahlen als übergebene Variable annehmen kann?

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11278

Du kannst keine Variablen in einer Brace Expansion verwenden, weil die Brace-Expansion vor der Variable-Expansion stattfindet. Als Alternative könntest du mit seq arbeiten:

1
for i in $(seq $startk $endk); do k="$(printf '%03d' "$i")"; echo wget $namestart$k$nameend; done

oder eine for-Schleife im C-Stil bauen, die eine Variable ausgehend vom Startwert inkrementiert, bis der gewünschte Wert erreicht wird:

1
for ((i=$startk; i<=$endk; i++)); do k="$(printf '%03d' "$i")"; echo wget $namestart$k$nameend; done

Mooi

Anmeldungsdatum:
15. August 2014

Beiträge: 187

In solchen fällen könnte man zu eval greifen:

for i in $(eval echo {$startk..$endk}) ...

empfehlen möchte ich diesen finsteren Hack allerdings nicht.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

Mooi schrieb:

In solchen fällen könnte man zu eval greifen:

for i in $(eval echo {$startk..$endk}) ...

empfehlen möchte ich diesen finsteren Hack allerdings nicht.

Da man dafür ja in der bash sein muss, kann man viel einfacher die zweite Lösung von seahawk1986 nehmen:

1
for ((i=$startk; i<=$endk; i++)); do k="$(printf '%03d' "$i")"; echo wget $namestart$k$nameend; done

Das vermeidet eval, was immer gewisse Sicherheitsrisiken birgt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ a=10
$ b='12}; echo beliebiges Kommando #'
$ set -x
$ for i in $(eval echo {$a..$b}); do echo $i; done
++ eval echo '{10..12};' echo '"beliebiges' 'Kommando"' '#}'
+++ echo 10 11 12
+++ echo 'beliebiges Kommando'
+ for i in $(eval echo {$a..$b})
+ echo 10
10
+ for i in $(eval echo {$a..$b})
+ echo 11
11
+ for i in $(eval echo {$a..$b})
+ echo 12
12
+ for i in $(eval echo {$a..$b})
+ echo beliebiges
beliebiges
+ for i in $(eval echo {$a..$b})
+ echo Kommando
Kommando

Man sieht in Zeile 7 wird einfach ausgeführt, was hinten in der Variable stand. Natürlich ist das Risiko eher gering, wenn man das Skript selbst schreibt und niemand ändern kann, was in der Variablen steht. Aber schon wenn man die Variable über die Argumentliste füllt und die Argumente vielleicht aus einer Quelle liest, die man nicht kontrolliert und prüft, steigt die Gefahr.

Antworten |