1

Я пытаюсь использовать Bash для завершения Project Euler 13. Ниже приведен мой код, с которым я просто не могу понять, в чем дело.

#!/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 "${sum:0:10}"                                         
exit 

Раньше это приводило к двум ошибкам,

(standard_in) 1: syntax error

а также

(standard_in) 1: illegal character: ^M

После некоторых исследований это, похоже, стало проблемой с терминаторами EOF. Затем я запустил на нем dos2unix, и он больше не выдает вторую ошибку, но все равно выдает первую повторно. Кажется, есть некоторая проблема с тем, как я передаю данные в bc, но я понятия не имею, что или как это исправить.

Правильный ответ 5537376230. Большое спасибо за все, что вы можете помочь!

Информация о системе

GNU bash, версия 4.3.11(1)-релиз (x86_64-pc-linux-gnu)

Я использую cmder на Windows 10.

2 ответа2

3

Вы хотите установить \n (== 0x0a == LF == перевод строки) в качестве разделителя read , а не \r (== 0x0d == CR == возврат каретки). Либо так, либо обязательно поставьте CR в конце вашего файла pastebin. Похоже, что в вашем файле pastebin отсутствует последовательность конца строки в конце последней строки, поэтому последняя строка никогда не передается в ваш скрипт.

$ 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

Обратите внимание, что между каждым числом есть 0x0d0a (CR LF), но не после последнего.

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

Обратите внимание, что последний номер, 535 [...] 690, отсутствует при выполнении команды read . Но если вы переключите свой разделитель на символ новой строки LF (\n) Unix, включится последняя строка:

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

Отредактировано, чтобы добавить: Вот исправление, которое обрабатывает CR в файле pastebin. Я сказал read чтобы использовать CRLF в качестве разделителя, и использовал дополнительное эхо, чтобы добавить CRLF после файла pastebin.

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 "${sum:0:10}"
3

Вы можете сделать это:

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

Что использует:

  • замена процесса, содержащая вызов curl и pipe в sed для удаления возвратов каретки.
  • перенаправить это в mapfile, чтобы прочитать строки ввода в массив оболочки
  • перебрать массив и вызвать bc с выражением, переданным здесь

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .