Warum liefert mein Bash-Skript nicht die richtige Antwort für dieses Project Euler?

703
Egrodo

Ich versuche, Bash zu verwenden, um Project Euler 13 abzuschließen . Unten ist mein Code, mit dem ich einfach nicht herausfinden kann, was falsch ist.

#!/bin/bash  sum=0  while read -r -d $'\r' line; do  sum=$(echo $sum + $line | bc)  done <<< "$(curl -s http://pastebin.com/raw/uHZ0PZjm)"  echo "$"  exit  

Es führte zu zwei Fehlern,

(standard_in) 1: syntax error 

und

(standard_in) 1: illegal character: ^M 

Nach einigen Recherchen schien es ein Problem bei den EOF-Terminatoren zu sein. Ich lief dann dos2unix darauf und es gibt den zweiten Fehler nicht mehr, aber der erste gibt immer noch den ersten Fehler. Es scheint ein Problem zu sein, wie ich die Daten in bc leite, aber ich habe keine Ahnung, was oder wie ich sie reparieren soll.

Die richtige Antwort lautet 5537376230. Vielen Dank für alles, womit Sie helfen können!

Systeminfo ist

GNU bash, Version 4.3.11 (1) -freigabe (x86_64-pc-linux-gnu)

Ich verwende cmder unter Windows 10.

1
Auf einer Ubuntu LTS-Bash-Shell wurde keine Fehlermeldung ausgegeben. Es antwortet "5483872696" ... Hastur vor 7 Jahren 1
Entschuldigung, sollte angegeben haben, die richtige Antwort ist 5537376230. Egrodo vor 7 Jahren 0
Ja, das solltest du (kein Problem, das hat mich und andere vielleicht nur davon abgehalten, weiter zu gehen), aber es gibt noch weitere Informationen ... es hat keinen Fehler erzeugt. Fügen Sie der Vollständigkeit halber die Betriebssystemversion hinzu, auf der Sie das Skript ausführen (Distribution, Release, Version von Bash ...). Es ist im Allgemeinen eine gute Angewohnheit und kann zum Verständnis beitragen. Hastur vor 7 Jahren 0
Okay, entschuldige, ich werde dies in Zukunft sicher tun. Danke für den Hinweis. Egrodo vor 7 Jahren 0
Nichts zu entschuldigen ... `:-)`. Übrigens ist es nur eine Frage von wenigen Sekunden, wirklich das Betriebssystem und die Version Ihres Systems hinzuzufügen. Ich bin immer noch neugierig darauf, den Grund für den `Syntaxfehler` zu kennen. Wenn Sie den Code in ein Skript auf meinem System einfügen, wird kein Fehler ausgegeben ... Hastur vor 7 Jahren 0
Ich habe gerade meine Systeminfo hinzugefügt! Egrodo vor 7 Jahren 0

2 Antworten auf die Frage

3
Spiff

Sie möchten \ n (== 0x0a == LF == Zeilenvorschub) als readTrennzeichen \rfestlegen, nicht (== 0x0d == CR == Wagenrücklauf). Entweder das oder stellen Sie sicher, dass Sie eine CR am Ende Ihrer Pastebin-Datei einfügen. Anscheinend fehlt in Ihrer Pastebin-Datei am Ende der letzten Zeile eine Zeilenabschlusssequenz, sodass die letzte Zeile niemals in Ihr Skript eingegeben wird.

$ curl -s http://pastebin.com/raw/uHZ0PZjm | hexdump -C | tail -n 8 ...(snip)... 000013e0 35 30 39 35 31 36 0d 0a 32 30 38 34 39 36 30 33 |509516..20849603| 000013f0 39 38 30 31 33 34 30 30 31 37 32 33 39 33 30 36 |9801340017239306| 00001400 37 31 36 36 36 38 32 33 35 35 35 32 34 35 32 35 |7166682355524525| 00001410 32 38 30 34 36 30 39 37 32 32 0d 0a 35 33 35 30 |2804609722..5350| 00001420 33 35 33 34 32 32 36 34 37 32 35 32 34 32 35 30 |3534226472524250| 00001430 38 37 34 30 35 34 30 37 35 35 39 31 37 38 39 37 |8740540755917897| 00001440 38 31 32 36 34 33 33 30 33 33 31 36 39 30 |81264330331690| 0000144e 

Beachten Sie, dass zwischen jeder Zahl ein 0x0d0a (CR LF) steht, nicht jedoch nach der letzten.

$ while read -r -d $'\r' line; do echo $line; done <<< "$(curl -s http://pastebin.com/raw/uHZ0PZjm)" | tail -n 3 77158542502016545090413245809786882778948721859617 72107838435069186155435662884062257473692284509516 20849603980134001723930671666823555245252804609722 

Beachten Sie, dass die letzte Zahl, 535 [...] 690, fehlt, wenn Sie Ihren readBefehl ausführen . Wenn Sie Ihr Trennzeichen jedoch auf das Zeilenumbruch-Zeichen Unix-native LF (\ n) umstellen, wird die letzte Zeile eingefügt:

$ while read -r -d $'\n' line; do echo $line; done <<< "$(curl -s http://pastebin.com/raw/uHZ0PZjm)" | tail -n 3 72107838435069186155435662884062257473692284509516 20849603980134001723930671666823555245252804609722 53503534226472524250874054075591789781264330331690 

Zum Hinzufügen bearbeitet: Hier ist ein Fix, der die CRs in der Pastebin-Datei behandelt. Ich habe gesagt read, CRLF als Trennzeichen zu verwenden, und ein zusätzliches Echo verwendet, um eine CRLF nach der Pastebin-Datei hinzuzufügen.

sum=0 while read -r -d $'\r\n' line; do sum=$(echo $sum + $line | bc) done <<< $(curl -s http://pastebin.com/raw/uHZ0PZjm; echo -e "\r\n") echo "$" 
Oh Gott, offensichtlich verschwendet Pastebin am Ende den Terminator, egal wie ich es einsetze, das ist srange. Ich habe die Zahlen stattdessen hart in mein Skript codiert und das CR-Trennzeichen beibehalten, wie Sie hier sehen können: http://pastebin.com/raw/g2iDchun. Aber aus irgendeinem Grund gibt das nur "0" zurück :( Wenn ich es in das LF-Trennzeichen \ n ändere, wird stattdessen "(standard_in) 2: Syntaxfehler") zurückgegeben. Irgendwelche Ideen, warum dies geschieht? Vielen Dank für Ihre Hilfe beim Aufräumen Unterschiede zwischen den Zeilenumbrüchen! Egrodo vor 7 Jahren 0
Ah, "bc" verschluckt sich, weil Ihr Pastebin CRs enthält. Als ich meine Änderung getestet habe, habe ich sie mit einem einfachen "Echo" getestet, ohne sie in "bc" zu leiten. Bei Ihrem neuen Problem behält die Shell Ihre Newlines in dieser Stringzuweisung nicht bei, sodass "$ numbers" eine lange Zeile mit Leerzeichen zwischen den Nummern ist. Spiff vor 7 Jahren 1
@Egrodo Okay, ich habe meine Answer mit einer echten, vollständig getesteten Lösung aktualisiert. Spiff vor 7 Jahren 1
Ich sehe, ich habe nicht gemerkt, dass die Shell keine Zeilenumbrüche erhalten hat, das ist ziemlich dumm. Ihre neue Lösung funktioniert perfekt. Vielen Dank für die Zeit, die Sie mir dabei geholfen haben. Wenn Sie nichts dagegen haben, versuche ich herauszufinden, was genau mit den Dingen passiert, die in die while-Schleife eingegeben werden. Also setze ich den Inhalt des Pastebins standardmäßig ein und gebe dann auch das Echo ein? Afaik, der das erledigte <<<-Ding tut, sagt einfach "gib diese Eingabe an irgendetwas in der Schleife, die nach Eingabe fragt". Wie wirkt sich das Echo darauf aus? Egrodo vor 7 Jahren 0
Ja, das Kommando <<< "string" `wird als" Here-String "bezeichnet, und es ist ungefähr dasselbe wie bei der Verwendung von` echo "String" | Befehl ". In Ihrem Fall verwenden Sie "$ (curl…; echo ...)", um aus der Standardausgabe von "curl" den "Here-String" zu bilden, gefolgt von der Standardausgabe von "echo". Beim Shell-Scripting werden die Befehle durch ein Semikolon getrennt, sodass Sie mehrere Befehle in eine Zeile schreiben können. Spiff vor 7 Jahren 1
3
glenn jackman

Du kannst das:

mapfile -t lines < <(curl -s http://pastebin.com/raw/uHZ0PZjm | sed 's/\r$//') sum=0 for bignum in "$"; do  sum=$(bc <<< "$sum + $bignum") done echo "$" # ==> 5537376230 

Das verwendet:

  • Eine Prozessersetzung, die den Aufruf enthält, sich zu locken und in sed zu leiten, um die Wagenrückläufe zu entfernen.
  • leiten Sie diese in mapfile um, um die Zeilen der Eingabe in ein Shell-Array zu lesen
  • iterieren Sie über das Array und rufen Sie bc mit dem übergebenen Ausdruck mit einer Here-Zeichenfolge auf