PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit Bashscripting - Ausgabe in Blöcken


RainingBlood
2014-01-17, 12:48:25
hi,

Ausgangslage:
eingelesen wird eine unbestimmte Anzahl an Parametern in einer Zeile.
Also z.b. 1 2 3 4 5 6 7 8 9 10 11 12 u.s.w.

Herauskommen sollen Blöcke à 3 Parameter:
1 2 3
4 5 6
7 8 9
10 11 12

Die Berechnung darf also nicht statisch sein.
Mehr als das krieg ich nicht zustande:
awk '{for (a=1; a<=3; a++) printf "%300s", $a}'
- so müsste ich das dann händisch für alle theoretisch möglichen Eingaben machen.

Wenn ich es mit einem array probiere, bekomme ich die Ausgabe nur untereinander:
1
2
3
u.s.w.


Ich verzweifle an dem Thema grad sehr :freak:

Ein richtungsweisender Hinweis würde reichen.

nalye
2014-01-17, 12:57:28
Versuch doch mal mit dem IFS zu arbeiten

RainingBlood
2014-01-17, 13:46:28
danke, komme allerdings nicht weiter

nalye
2014-01-17, 14:28:51
Sehr(!) quick und dirty, aber tut... Die while-Schleife kann man auch noch automatisieren, bin ich aber gerade nicht so wirklich dazu zu begeistern.

root@testhobel:~# cat block
1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
root@testhobel:~# cat seperate.sh
#!/usr/bin/env bash

S=0

while IFS=$' ' read -r -a myArray
do
echo -n ${myArray[$S]}
S=`expr $S + 1`
echo -n ${myArray[$S]}
S=`expr $S + 1`
echo -n ${myArray[$S]}
S=`expr $S + 1`
echo ""
echo -n ${myArray[$S]}
S=`expr $S + 1`
echo -n ${myArray[$S]}
S=`expr $S + 1`
echo -n ${myArray[$S]}
S=`expr $S + 1`
echo ""
echo -n ${myArray[$S]}
S=`expr $S + 1`
echo -n ${myArray[$S]}
S=`expr $S + 1`
echo -n ${myArray[$S]}
S=`expr $S + 1`
echo ""

done < block
root@testhobel:~# ./seperate.sh
123
456
789

RainingBlood
2014-01-17, 20:19:39
Statisch ok, aber dynamisch schnall ich es einfach nicht.
Projekt für die HK Prüfung kommt gerade sehr ins Stocken. Genau dieses Stück brauch ich zum Abschluss, um alle anderen Skripte zusammenfügen zu können^^.

Hast du vllt. eine gute Seite für Infos?

Gast
2014-01-17, 20:51:57
Kling nach einer geschachelten Schleife, da du ja schon selbst awk vorgeschlagen hast:

{
for(i=0;i<NF;i+=3) {
for(j=0;j<3;j++) {
printf("%300s",$(i+j));
}

printf("\n");
}
}


Syntaktisch sicher falsch, vielleicht noch n Bug drin, aber die Idee sollte klar sein.

RainingBlood
2014-01-18, 17:58:30
okay, das ist interessant. Ich werds Montag gleich mal ausprobieren. Big thx!

PHuV
2014-01-19, 02:43:52
Kling nach einer geschachelten Schleife, da du ja schon selbst awk vorgeschlagen hast:

Hat wieder den Nachteil von Laufzeit und vielen Forks!
Ich verwende mal die Datei block von nalye. Bei Argumenten müßte man $* verwenden.

Die erste Lösung ist schneller, und funktioniert auch mit ksh, die zweite Lösung ist mit einem Array und For-Schleife, geht aber nur mit bash!!!
Beide Lösungen sind auf alle Fälle schneller als die vorher genannten, wenn Performance benötigt wird (bei sehr großen Dateien)

#!/bin/bash

Datei=block
# Schicker: Datei als Argument übergeben
# Datei=$1
# shift 1

# 1.Lösung
zz=0

# lies einfach alles ein
for var in `cat ${Datei}`
do
# gibt ein Element bitte ohne Umbruch aus
echo -e "$var \c"
# schön mitzählen
zz=$((zz+1))
# wenn modulo 3, dann machen Umbruch
if [ $((zz%3)) == 0 ];then
echo ""
# oder
# echo -e "\n"
fi
done
# Dann schön noch einen Zeilenumbruch am Ende
echo ""

# 2.Lösung
# Achtung, geht nur mit bash!!!

# Datei in ein Array lesen
array=( `cat ${Datei}` )
# Ausgabe der Anzahl der Elemente im Array
# echo "MAX ${#array }"
# Solange das Array voll ist, schreibe 3 Elmente raus, und zähle bis 3 weiter
for(( i=0; i< ${#array } ; ((i=i+3)) ))
do
echo "${array[$i]} ${array[$i+1]} ${array[$i+2]}"
done

exit 0

Gast
2014-01-20, 20:01:50
Hat wieder den Nachteil von Laufzeit und vielen Forks!
Dass ein Einwand wegen Laufzeit kommt habe ich geahnt - aber der Schein trügt:
Wenn man es in eine Schleife packt (wie auch immer) hat man O(n).
Mit der verschachtelten Schleife hat man O(n) * O(1) => O(n) - also dieselbe Laufzeit. (Oder anders: Die innere Schleife hat konstante Laufzeit und ist daher irrelevant).

Aber was meinst du mit Forks!?

nalye
2014-01-20, 22:17:03
Hängste eben ein "time" vor das jeweilige Programm und dann passt das schon. Ich denke mal, dass PHuV mit Forks die jeweiligen "printf"-Aufrufe meint, die gestartet werden...

del_4901
2014-01-20, 22:59:46
Stichwort: Duffs Device

nalye
2014-01-20, 23:37:36
Na ja, Duffs Device ist eher für ältere Geschichten gut, die Shell hat eigentlich ganz gute Funktionen, um Schleifen effizient durchzugehen. Aber zum Lernen ist das natürlich ein sehr gutes Stichwort.

//Edith meint: Eigentlich wollte er ja nur einen Denkanstoß, jetzt kauen wir das doch halb vor ;)

PHuV
2014-01-21, 01:06:18
Aber was meinst du mit Forks!?
Damit meine ich einen Unix Fork, ein vom Shellscript aufgerufenen Systemaufruf, um ein weiteres Programm zu starten. Ein Fork macht immer einen neuen Prozess auf Betriebssystemebene auf. Das kann ein cut, cat, awk, expr usw. sein, siehe Beispiel hier (http://www.forum-3dcenter.org/vbulletin/showpost.php?p=9973204&postcount=18). Wenn Du ein awk verwendest, um beispielsweise ein printf zu machen, und das 1000 mal, dann machst Du 1000 mal einen neuen Aufruf vom AWK. Und das bremst gewaltig. Mit p(s)tree pid kann man das schön sehen.

Man braucht nur mal den Vergleich von meinem Beispiel (http://www.forum-3dcenter.org/vbulletin/showpost.php?p=9973204&postcount=18)mit ein bißchen mehr Daten laufen zu lassen, und man bemerkt sofort den Laufzeitunterschied. Deshalb verwende ich heute, wenn es möglich und machbar ist, immer Inline-Befehle der ksh und bash. Die sind deutlich schneller.

Gast
2014-01-23, 17:18:29
Ok, meine Frage war sehr unspezifisch - ich weiß was ein Fork ist.
Mein Code ist aber für 1 awk-Instanz gedacht und es wäre mir neu, dass awk einen Fork macht, um ein printf auszuführen.

Ich hab das auch gerade nochmal mit pstree getestet und konnte nichts dergleichen feststellen.


{
for(i=0;i<NF;i+=3) {
...

NF ist eine Variable / reserviertes Wort in awk, das die Anzahl an Wörtern enthält. Die Schleife würde deshalb außerhalb von awk gar nicht funktionieren.

Hat sich ein Mißverständnis geklärt oder bin ich völlig schief gewickelt? :)


Zu deinem verlinkten Posting: `` durch $() zu ersetzen ist leider nicht immer eine gute Idee, da `` portabel ist, $() nicht.

sei laut
2014-01-25, 17:50:41
//Edith meint: Eigentlich wollte er ja nur einen Denkanstoß, jetzt kauen wir das doch halb vor ;)
Vorallem, da die Logik dahinter an sich ja nicht wirklich schwer ist.
Er muss es sowieso anpassen und kanns nicht übernehmen, da die Antworten hier ja auffindbar sind und ers für eine Prüfung braucht. ;D

Gast
2014-02-13, 21:20:30
Es waren zwar nur Hinweise gefragt, aber es sind ja schon ein paar Tage vergangen:

$ echo 1 2 3 4 5 6 7 8 9 10 | awk '{for(i=1;i<=NF;i+=3) { printf("%s %s %s\n", $i, $(i+1), $(i+2)) }}'
1 2 3
4 5 6
7 8 9
10


Und von einem Kollegen:

$ echo 1 2 3 4 5 6 7 8 9 10 | xargs -n 3
1 2 3
4 5 6
7 8 9
10

PHuV
2014-02-13, 23:59:42
Das mit dem xargs -n 3 ist ja eine schicke Lösung, solltest Du gleich mal in die Scriptsammlung aufnehmen.

sei laut
2014-03-18, 11:17:24
Wenn man das schön untereinander haben will, hilft column -t
echo "2383 338 32 2 2 45 32 2" | xargs -n3 | column -t -s " "
2383 338 32
2 2 45
32 2