Können Sie diese Bash Scripting-Übung lösen?

Wenn Sie It's FOSS auf Facebook folgen, sind Sie möglicherweise über die wöchentliche Bash Challenge informiert. Es ist eine gemeinsame Anstrengung von Yes I Know It und It's FOSS, Ihnen eine Bash-Skript-Übung zu geben, um Ihre Linux-Fähigkeiten zu testen.

Wir bringen diese Bash Challenge von Facebook einem breiteren Publikum im regulären Web. Dies ist die 5. Folge dieser Serie. Die ersten 4 Herausforderungen finden Sie auf unseren Facebook-Seiten. Sie können diese Herausforderungen auch in Buchform kaufen:

Bash Challenge 5

Wir zeigen Ihnen einen Terminal-Screenshot und bitten Sie zu erklären, warum das Ergebnis nicht das erwartete ist. Natürlich besteht der amüsanteste und kreativste Teil der Herausforderung darin, zu finden, wie die auf dem Bildschirm angezeigten Befehle korrigiert werden können, um das richtige Ergebnis zu erzielen.

Fertig zu spielen? Also hier ist die Herausforderung dieser Woche:

Mein Bash kann nicht zählen [Schwierigkeitsgrad 1]

Diese Woche habe ich eine Datendatei mit ganzzahligen Zahlen, eine in jeder Zeile:

cat sample.data 102 071 210 153 

Und ich möchte die Summe all dieser Zahlen berechnen:

 declare -i SUM=0 while read X ; do SUM+=$X done < sample.data echo "Sum is: $SUM" 

Leider ist das Ergebnis, das ich erhalte, falsch (das erwartete Ergebnis war 536):

 Sum is: 522 

Herausforderung

Ihre Herausforderung besteht darin, Folgendes zu finden:

  • Warum war das Ergebnis falsch?
  • Wie kann ich meine Befehle korrigieren, um das richtige Ergebnis zu erzielen?

★ Bonus Einhorn Punkt, wenn Sie eine Lösung finden können, die nur interne Bash-Befehle und / oder Shell-Ersetzungen verwendet.

Wir freuen uns darauf, Ihre Lösungen im Kommentarbereich weiter unten zu lesen! Vergiss nicht kreativ zu sein.

Einige Details

Um diese Herausforderung zu erstellen, habe ich Folgendes verwendet:

  • GNU Bash, Version 4.4.5 (x86_64-pc-linux-gnu)
  • Debian 4.8.7-1 (amd64)
  • Alle Befehle werden mit einer Standard-Debian-Distribution ausgeliefert
  • Kein Befehl wurde voreingenommen

Lösung

Wie reproduzieren

Hier ist der Rohcode, mit dem wir diese Herausforderung erstellt haben. Wenn Sie das in einem Terminal ausführen, können Sie genau dasselbe Ergebnis wie in der Abbildung zur Abfrage reproduzieren (vorausgesetzt, Sie verwenden dieselbe Softwareversion wie ich):

 rm -rf ItsFOSS mkdir -p ItsFOSS cd ItsFOSS cat > sample.data << 'EOT' 102 071 210 153 EOT clear cat sample.data declare -i SUM=0 while read X ; do SUM+=$X done < sample.data echo "Sum is: $SUM" 

Was war das Problem ?

Das Problem wurde durch den Wert 071 verursacht. Wie Sie bemerkt haben, beginnt diese Zahl mit einer 0 - wahrscheinlich, um hier sicherzustellen, dass alle Daten dreistellig formatiert sind. Hier ist nichts komplizierter, außer dass… nach einer unglücklichen Konvention, die von der Programmiersprache C geerbt wurde, das Präfixieren einer Ganzzahl mit 0 eine Möglichkeit ist, diese Zahl in Oktal und nicht in Dezimal anzugeben.

Oktalzahlen werden mit Ziffern von 0 bis 7 ausgedrückt. Hier ist eine einfache Umrechnungstabelle:

OktalDezimal
00
11
22
33
44
55
66
77
108
119
1210
1311
1412
....
7157

Dieser letzte Wert hat den Fehler bei der Auswertung der Summe verursacht. Der Bash las 071 und interpretierte es als eine Oktalzahl, die den 57 Dezimalwert darstellt. Das können Sie ganz einfach überprüfen:

 echo $((071)) 57 

Wie kann man das beheben?

Ich sehe zwei Hauptstrategien, um dieses Problem zu beheben. Entweder die führenden Nullen entfernen. Oder einen Weg zu finden, die Shell zu verstehen, dass alle meine Zahlen Dezimalwerte sind.

Führende Nullen entfernen

Hier ist eine einfache Lösung, bei der die führenden Nullen mit dem Befehl sed external entfernt werden:

 declare -i SUM=0 while read X ; do SUM+=$X done < <(sed -E s/^0+// sample.data) echo "Sum is: $SUM" 

(Bonusfrage: Warum habe ich keine Pipe anstelle einer Prozessersetzung verwendet ?)

Basis explizit angeben

Die vorherige Lösung ist (meistens) unkompliziert - aber mit der Bash können wir die Dinge verbessern. Anstatt zu versuchen, die Daten zu korrigieren, geben wir einfach explizit an, dass unsere Zahlen in Basis 10 (dezimal) anstelle von Basis 8 (oktal) ausgedrückt werden. Sie können dies mithilfe der base#value Syntax tun.

Vergleichen Sie diese drei Beispiele:

 echo $((071)) # The leading `0` specify the number as octal 57 echo $((8#071)) # We *explicitly* specify base 8 (octal) 57 echo $((10#071)) # We *explicitly* specify base 10 (decimal) 71 

Um meinen anfänglichen Befehl zu korrigieren und das richtige Ergebnis zu erhalten, muss ich nur die Basis 10 für alle meine Daten explizit angeben:

 declare -i SUM=0 while read X ; do SUM+=$((10#$X)) done < sample.data echo "Sum is: $SUM" 

Und hier ist das richtige Ergebnis. Wir hoffen, Ihnen hat diese Herausforderung gefallen. Bleiben Sie dran für mehr Spaß!

Autor Bio: Ich bin Sylvain Leroux, ein Software-Ingenieur aus Leidenschaft, ein Lehrer aus Berufung. Ich habe 15 Jahre Erfahrung im Unterrichten von Informatik und Informationstechnologien auf allen Ebenen. Ich bin ein starker Verfechter der Linux- und OpenSource-Technologien. Ich habe Yes I Know IT gegründet, um diese Erfahrung mit Online-Kursen und kostenlosen Videos einem breiteren Publikum zugänglich zu machen. Zögern Sie nicht, mich auf Twitter zu erreichen.

Empfohlen

Tracktions T7 DAW kann jetzt kostenlos unter Linux heruntergeladen werden
2019
Solus Version 1.2.1 bringt Mate Desktop
2019
Die JavaScript-Engine von Microsoft Edge soll Open Source sein
2019