Можеш ли да решиш това упражнение за скриптове?

Ако следвате FOSS във Facebook, може да сте наясно със седмичния Bash Challenge. Това е съвместно усилие от Да, аз го познавам и е FOSS, за да ви даде упражнение за скрипт на Bash, за да тествате вашите Linux умения.

Предоставяме това предизвикателство Bash от Facebook на по-широка аудитория в редовната мрежа. Това е петата част от тази серия. Първите 4 предизвикателства могат да бъдат намерени на нашите Facebook страници. Можете също така да закупите тези предизвикателства под формата на книга:

Bash Challenge 5

Ще ви покажем снимка от терминала и ще ви помоля да обясните защо резултатът не е този, който очаквахме. Разбира се, най-забавната и най-креативната част от предизвикателството ще бъде да се намери как да се коригира показаната на екрана команда (и), за да се получи правилния резултат.

Готов за игра? Ето това е предизвикателството тази седмица:

Моят Баш не знае как да брои [Ниво на трудност 1]

Тази седмица имам файл с данни, съдържащ цели числа, по един за всеки ред:

cat sample.data 102 071 210 153 

Искам да изчисля сумата на всички тези числа:

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

За съжаление резултатът, който получавам, е грешен (очакваният резултат е 536):

 Sum is: 522 

Предизвикателство

Предизвикателството ви е да намерите:

  • Защо този резултат е грешен?
  • Как да поправя командите си за получаване на правилния резултат?

★ Бонус еднорог точка, ако можете да намерите решение, използвайки само вътрешни команди Bash и / или замествания на обвивката.

Очакваме с нетърпение да прочетете вашите решения в раздела за коментари по-долу! Не забравяйте да бъдете креативни.

Малко подробности

За да създам това предизвикателство, използвах:

  • GNU Bash, версия 4.4.5 (x86_64-pc-linux-gnu)
  • Debian 4.8.7-1 (amd64)
  • Всички команди са тези, които се доставят със стандартна дистрибуция на Debian
  • Нямаше никаква команда

Решение

Как да се възпроизвежда

Това е суровият код, който използвахме, за да произведем това предизвикателство. Ако изпълните това в терминал, ще можете да възпроизведете точно същия резултат, както е показано в илюстрацията на предизвикателството (ако използвате същата софтуерна версия като мен):

 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" 

Какъв беше проблема ?

Проблемът се дължи на стойността 071 . Както забелязахте, този номер започва с 0 - вероятно за да се гарантира, че всички данни са форматирани на три цифри. Тук няма нищо сложно, с изключение на това, че ... след злощастната конвенция, наследена от езика за програмиране от С, префиксирането на цяло число с 0 е начин да се уточни, че числото е изразено в осмичното, а не в десетичната .

Окталните числа се изразяват с цифри от 0 до 7 . Ето една проста таблица за реализации:

Осмичендесетичен
00
11
22
33
44
55
66
77
108
119
1210
1311
1412
....
7157

Тази последна стойност е причината за грешката при оценката на сумата. Баш прочете 071 и го интерпретира като осмично число, представляващо 57 десетична стойност. Можете лесно да проверите:

 echo $((071)) 57 

Как да поправя това?

Виждам две основни стратегии за отстраняване на този проблем. Или премахване на водещите нули. Или намирането на начин да разберем всичките ми числа са десетични стойности.

Премахване на водещи нули

Ето просто решение, използващо командата sed external за премахване на водещите нули:

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

(бонус въпрос: защо не използвах тръба, вместо заместване на процеса ?)

Изрично задаване на базата

Предишното решение е (най-вече) просто - но Баш ни позволява да направим нещата по-добри. Вместо да се опитваме да поправим данните, ние просто ще посочим изрично нашите числа да бъдат изразени в база 10 (десетичен), вместо база 8 (осмична). Можете да направите това, като използвате синтаксиса на base#value .

Сравнете тези три примера:

 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 

За да коригирам първоначалната си команда и да получа правилния резултат, трябва само изрично да посоча базата 10 за всичките ми данни:

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

И тук е правилният резултат. Надяваме се, че ви харесва това предизвикателство. Останете на линия за по-голямо удоволствие!

Автор Био: Аз съм Силвен Леру, софтуерна инженер по страст, учител по призвание. Имам 15 години опит в преподаването на компютърни науки и информационни технологии на всички нива. Аз съм силен защитник на Linux и OpenSource технологии. Създадох да знам IT, за да споделя този опит с по-широка публика чрез онлайн курсове и безплатни видеоклипове. Не се колебайте да се свържете с мен в Twitter.

Препоръчано

Пълно ръководство за трикратно зареждане на Windows, Kubuntu и Debian
2019
GNOME 3.26 Издаден! Проверете новите функции
2019
3D отпечатване с отворен код: проучване на научни и медицински решения
2019