ubuntuusers.de

Zahlenvariablen richtig abspeichern

Status: Gelöst | Ubuntu-Version: Xubuntu 16.04 (Xenial Xerus)
Antworten |

KeyzerSoze

Anmeldungsdatum:
28. September 2014

Beiträge: 120

Hallo,

hier ist ein kurzes Skript:

(
for i in {50..150}
do
echo ""$i".txt"
done
) > meinekonfigurationsdatei.in

Das liefert als Ausgabe:

50.txt
51.txt
...
100.txt
...
150.txt

Ich möchte aber folgende Ausgabe:

050.txt
051.txt
...
100.txt
...
150.txt

Kurz gesagt, es geht mir um die "0" vor den Zahlen unter 100.

Kann mir jemand weiterhelfen?

Vielen Dank im Voraus!

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11250

Wohnort: München

Du kannst einfach angeben, dass er von 050 bis 150 zählen soll:

(
for i in {050..150}
do
echo ""$i".txt"
done
) > meinekonfigurationsdatei.in

KeyzerSoze

(Themenstarter)

Anmeldungsdatum:
28. September 2014

Beiträge: 120

Ja, danke schon mal. Sorry, ich habe die Frage leider schlampig gestellt.

Ich habe statt

for i in {50..150} 

folgendes in meinem Skript stehen:

for i in $(eval echo "{$startzahl .. $endzahl}") 

und da kommt es vor, dass

echo "$startzahl"<100 und echo "$endzahl">100

. Die Variablen

startzahl und endzahl

lese ich mit read ein. Ich fürchte, ich komme ohne if-Schleife nicht weiter, oder?

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11250

Wohnort: München

Man könnte auch vorab mit printf die führende Null einfügen, falls nötig:

startzahl=$(printf "%03d" $startzahl)
for i in $(eval echo "{$startzahl .. $endzahl}") 

KeyzerSoze

(Themenstarter)

Anmeldungsdatum:
28. September 2014

Beiträge: 120

seahawk1986 schrieb:

Man könnte auch vorab mit printf die führende Null einfügen, falls nötig:

startzahl=$(printf "%03d" $startzahl)

Sehr elegant ☺ Das löst mein Problem! Danke vielmals!

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Vielleicht noch 3 Anmerkungen:

  1. Das eval ist hier überflüssig, und sogar gefährlich: denn man kann an dieser Stelle sonst was für Schadcode einschleusen,

  2. eine Untershell brauchst Du auch nicht: Du kannst die Datei-Umleitung direkt an die Schleife anhängen,

  3. und wildes "Quoting" ist ist auch nicht professionell, sondern einfach nur Quatsch.
    Im Grunde brauchst Du hier nix "quoten", denn Du hast ja fast nur Zahlen:

1
2
3
4
5
n1=5
n2=11
for (( i=n1; i<=n2; i++ )); do
    printf  %3.3i.txt\\n  $i
done  >  meinekonfigurationsdatei.in

(Ja, ein einziges Zeichen habe ich \escaped: sonst hätte er den Zeilenumbruch "\n" nicht verstanden.)

LG,

track

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17605

Wohnort: Berlin

For sowas brauchts kein for:

1
echo -e "\n"{099..101}".txt" | sed '1d' > meinekonfigurationsdatei.in

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13176

Warum so umständlich? Das geht doch viel einfacher so

1
printf '%03d.txt\n' {50..150} > meinekonfigurationsdatei.in

KeyzerSoze

(Themenstarter)

Anmeldungsdatum:
28. September 2014

Beiträge: 120

Okay, als Themensteller bin ich vollkommen gescheitert ☹ Mir tut es Leid, dass sich die Aufgabenstellung wieder ein wenig verändert. Ich dachte ich würde es mit Euren Hilfestellungen hinkriegen, aber dem ist leider nicht so ☹

Was ich als Ergebnis brauche, ist folgendes:

  050name.txt     
  50                                                                                                
  30 (ohne Null davor)
  und
  noch
  viel konstanter Text (mit grep)
  051name.txt      
  51                                                                                               
  31 (ohne Null davor)
  und
  noch
  viel konstanter Text (mit grep)
  052name.txt         
  52                                                                                            
  32 (ohne Null davor)
  und
  noch
  viel konstanter Text (mit grep)
  ...
  100name.txt        
  100                                                                                             
  80 (ohne Null davor)
  und
  noch
  viel konstanter Text (mit grep)
  ...
  120.name.txt
  120
  100 (ohne Null davor)
  und
  noch
  viel konstanter Text (mit grep)

Bemerkung1: 050 (der Laufindex) soll als Variable mittels read eingelesen werden. }}} Bemerkung2: die 3. Zahl, im Beispiel 30, soll eine konstante Verschiebung vom Laufindex sein. [ich hätte es mir so vorgestellt:

 $ (( i - 20 ))

, aber das klappt nicht, weil wenn z.B. das "i" = 058 ist, dann zeigt er mir einen Fehler an]

Ich hätte eben gedacht, dass für diese Aufgabe eine For-schleife praktisch ist, weil viel konstanter Text kopiert wird.

Nochmal sorry, dass ich nicht gleich die ganze Aufgabenstellung hingeschrieben habe ☺

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Das Problem bei solchen Zahlen mit führender Null ist (in der Shell !), dass sie dann als oktal verstanden werden. (→ hier im letzten Abschnitt)

Also: solche Zahlen grundsätzlich entweder ohne führende Null, oder ausdrücklich mit der Basisangabe 10 (→ "10#080"), oder gleich was anderes nehmen:

track@track:~$ for i in {99..101}; do printf "%3.3iname.txt\n%i\n%i\nviel Text ...\n...\n" $i $i $((i-20)); done
099name.txt
99
79
viel Text ...
...
100name.txt
100
80
viel Text ...
...
101name.txt
101
81
viel Text ...
...
track@track:~$ for i in {099..101}; do echo -e "${i}name.txt\n$((10#$i+0))\n$((10#$i-20))\nviel Text ...\n..."; done
099name.txt
99
79
viel Text ...
...
100name.txt
100
80
viel Text ...
...
101name.txt
101
81
viel Text ...
...
track@track:~$ awk 'BEGIN {for(i=99; i<=101; i++) printf ("%3.3iname.txt\n%i\n%i\nviel Text ...\n...\n",i,i,i-20)}'
099name.txt
99
79
viel Text ...
...
100name.txt
100
80
viel Text ...
...
101name.txt
101
81
viel Text ...
... 

LG,

track

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13176

KeyzerSoze schrieb:

Okay, als Themensteller bin ich vollkommen gescheitert ☹ Mir tut es Leid, dass sich die Aufgabenstellung wieder ein wenig verändert.

Ja, das ist nicht so hilfreich und führt meist zu Verwirrung.

Was ich als Ergebnis brauche, ist folgendes:

Was ist "Text (mit grep)"?

Bemerkung1: 050 (der Laufindex) soll als Variable mittels read eingelesen werden.

Von der Konsole (also einem Menschen) oder aus einer Datei? Und wozu? Vielleicht erklärst Du doch mal den gesamten Use Case.

Bemerkung2: die 3. Zahl, im Beispiel 30, soll eine konstante Verschiebung vom Laufindex sein. [ich hätte es mir so vorgestellt:

 $ (( i - 20 ))

, aber das klappt nicht, weil wenn z.B. das "i" = 058 ist, dann zeigt er mir einen Fehler an]

Siehe tracks Erläuterungen zu Zahlensystemen. Ich denke, die führenden Nullen produziert man am besten erst bei der Ausgabe (z.B. mit printf).

Ich hätte eben gedacht, dass für diese Aufgabe eine For-schleife praktisch ist, weil viel konstanter Text kopiert wird.

Wenn wir mal wüssten, was "diese Aufgabe" eigentlich ist...

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17605

Wohnort: Berlin

Bemerkung1: 050 (der Laufindex) soll als Variable mittels read eingelesen werden.

Dann scheidet {von..bis} (Shellinternal) leider aus und Du musst entweder zu einer for-loop greifen, oder mit seq arbeiten.

1
2
3
4
a=99; for i in $(seq $a $((a+3)))
do
  printf "foo %3.3d.name bar\nfoobar $i $((i-20))\nipsum lore\n\n" $i
done

KeyzerSoze

(Themenstarter)

Anmeldungsdatum:
28. September 2014

Beiträge: 120

Vielen Dank Euch allen, es funktioniert wunderbar ☺

rklm schrieb:

Was ist "Text (mit grep)"?

Ich wollte damit sagen, dass ich grep-Funktionen verwenden möchten. Mit den präsentierten Lösungen funkioniert das wunderbar ☺

Vielleicht erklärst Du doch mal den gesamten Use Case. Wenn wir mal wüssten, was "diese Aufgabe" eigentlich ist...

Ich schreibe eine Konfigurationsdatei für ein Fortranprogramm, das ich mit einem weiteren Bashskript in einem Loop ausführe und dabei kontinuierlich bei jedem Loopschritt ein Stück Konfigurationsdatei automatisch einlesen lasse.

track schrieb:

Vielleicht noch 3 Anmerkungen:

  1. Das eval ist hier überflüssig, und sogar gefährlich: denn man kann an dieser Stelle sonst was für Schadcode einschleusen,

  2. eine Untershell brauchst Du auch nicht: Du kannst die Datei-Umleitung direkt an die Schleife anhängen,

  3. und wildes "Quoting" ist ist auch nicht professionell, sondern einfach nur Quatsch.

Punkt 2 und 3 sehe ich sofort ein ☺

Punkt 1 ist mir noch nicht klar: Nächstes Mal werde ich seq verwenden, wenn das sicherer ist ☺

n1=3
n2=5
for i in $(echo {$n1..$n2});do echo $i.txt; done

Liefert:
{3..5}.txt
n1=3
n2=5
for i in $(eval echo {$n1..$n2});do echo $i.txt; done

Liefert:
3.txt
4.txt
5.txt
n1=3
n2=5
for i in $(seq $n1 $n2); do echo $i.txt; done

Liefert:
3.txt
4.txt
5.txt

Kannst Du bitte beschreiben inwiefern ich eval weglassen kann, in meinem Minimalbeispiel funktioniert es nämlich nicht ☹

user_unknown schrieb:

1
2
3
4
a=99; for i in $(seq $a $((a+3)))
do
  printf "foo %3.3d.name bar\nfoobar $i $((i-20))\nipsum lore\n\n" $i
done

Prinzipiell finde ich diese Lösung sehr schön, ich verstehe nur 2 Sachen nicht:

  1. Wie weiß das Programm, dass das

    %3.3d

    der Laufindex ist.

  2. Was macht das (für mich) misteriöse $i außerhalb der printf-Umgebung?

Viele Grüße und besten Dank!

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Das gefährliche an eval ist, dass Du dort über die Variablen jedweden Schadcode einfügen kannst:

track@track:~$ n1=9
track@track:~$ n2=11
track@track:~$ for i in $(eval echo "{$n1..$n2}") ; do echo $i; done
9
10
11
track@track:~$ n1="}; date; "
track@track:~$ for i in $(eval echo "{$n1..$n2}") ; do echo $i; done
..11}: Befehl nicht gefunden.
{}
Di
17.
Jan
22:09:08
CET
2017 

Hier habe ich symbolisch mal nur den date- Befehl eingeschleust, und der wird ausgeführt. Aber das könnte ja durchaus was Bösartigeres sein ... 😉

Ein seq würde ich gar nicht mal nehmen: zu umständlich. Du kannst in der for- Schleife direkt Variablen einfügen,
so wie ich es schon in meinem 1. Beitrag gezeigt habe.

Bei der printf - Formatierung wird der Reihe nach für jeden Platzhalter die jeweilige Variablen dahinter eingesetzt.
Lies es mal im prinf- Wiki nach ...

LG,

track

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17605

Wohnort: Berlin

KeyzerSoze schrieb:

user_unknown schrieb:

1
2
3
4
a=99; for i in $(seq $a $((a+3)))
do
  printf "foo %3.3d.name bar\nfoobar $i $((i-20))\nipsum lore\n\n" $i
done

Prinzipiell finde ich diese Lösung sehr schön, ich verstehe nur 2 Sachen nicht:

  1. Wie weiß das Programm, dass das

    %3.3d

    der Laufindex ist.

Ist es nicht. Das ist ein Formatierungsstring für ein Argument, der später zugegeben wird.

  1. Was macht das (für mich) misteriöse $i außerhalb der printf-Umgebung?

Das ist das Argument.

1
2
printf "%4.4d Brötchen für %2.2d Esser\n" 916 916 
0916 Brötchen für 916 Esser

Das kann eine literale Zahl sein, eine Variable, das Ergebnis einer Berechnung oder die Ausgabe eines Programms oder einer Funktion.

Siehe auch help printf und man -a printf.

Ich finde die Formatierungsstrings schwer durchschaubar und halte mich daher davon fern. Was "%4.4d" bedeutet weiß ich nicht wirklich. % leitet den String ein, d steht für digits, 4 irgendwie für 4 Stellen aber wieso 4.4?

Antworten |