Секрети в Bash для початківців: оптимізація для Linux і DevOps

💡 Усі статті, обговорення, новини про DevOps — в одному місці. Приєднуйтесь до DevOps спільноти!

На зображенні випадковий код для привернення уваги :)

Привіт всім. Я багато років працюю на різних посадах інфраструктурного інженера та хочу розказати про декілька моментів щодо shell-скриптів.
Мої перші мови — BASIC та Assembler, перші батники ще в DOS та Windows 9x, і на них я робив багато автоматизації адміністрування.

Я взагалі досі вважаю себе прихильником Windows.
Але вважаю, що shell-скриптинг дуже незаслужено недооцінюють. shell-скрипти дуже глибоко проникли в *nix і технічно й ідеологічно, вони виросли разом з *nix, а пізніше з Linux та стандартами POSIX.

Найпопулярніший shell інтерпретатор — це bash. Але озираючись на сумісність, потрібно відрізняти POSIX shell від bash, бо деякі нововведення в bash не підтримуються в більш простих оболонках, таких як sh чи dash. Інши сучасні інтерпретатори zsh, fish — можуть навіть більше, особливо в адмініструванні.
В DevOps практиках я намагаюсь користуватися найбільш поширеними або вже встановленими інструментами для сумісності та скороченню технологічного стеку, тому пишу на bash чи на POSIX-сумісному шелл.
Це важливо, бо в сучасному світі ви можете зустріти саме простіший POSIX shell в embedded чи контейнерах.

У статті я для спрощення буду писати bash, якщо це буде важливо, окремо буду писати POSIX shell.

Зазвичай bash, на відміну від універсальних скриптових мов програмування, використовується найчастіше для роботи з іншими продуктами, а не у ролі самостійних застосунків.

Тобто на bash пишуть різні враппери, адміністративні скрипти для конфігурації та інсталяції, скрипти для бекапу, збірки та створення пакетів, пайплайнів, моніторингові грабери, «клей» для інтеграції різних продуктів, підготовки оточення та інші проміжні речі.
Бо він під рукою майже всюди і є велика кількість потужного консольного софта, який дуже і дуже легко інтегрувати саме в bash-скрипт.

Також в продакшені bash може бути дуже мало, а ось у CI/CD та адмініструванні він зустрічається набагато частіше, тому його знання для адмінів та DevOps-ів обов’язкове.

Звісно, можна писати і самостійні програми на bash (в мене є такі, наприклад ось), але зазвичай він не дуже оптимізований під перформанс, тому це скоріше спортивне програмування чи персональні звички або окремі потреби (є й таке). Але bash — це повноцінна скриптова мова, із своїми таємницями та перевагами.

На жаль, багато айтішніків, які вважають bash дуже простим, навіть не намагаються прочитати основи документації. Пишуть навмацьки, тому і роблять багато архітектурних помилок та лаються на неінтуїтивну поведінку.

Ця стаття не має якусь велику ціль чи конкретний топік, я хочу просто розібрати декілька рандомних прикладів, які досить часто зустрічаються в bash-скриптингу.

Зміст:

1. Розбиваємо строку
2. Розберемося з перенаправленнями інпуту, а саме <, << та <<<
3. Простий приклад FizzBuzz та навіщо писати #!/usr/bin/env bash
4. Autocomplete
5. read замість sleep
6. Лапки....

1. Розбиваємо строку

Цей приклад зустрічається повсякденно. Треба розбити строку на декілька значень чи викусити щось із структурованої або поганоструктурованої строки. Наприклад, маємо строку «c1 c2 c3». Треба прочитати значення другої колонки.

A) Багато хто використовує cut, просту команду, що створена саме для таких цілей:

$ echo "c1 c2 c3" | cut -d " " -f 2
c2

B) Дехто користується awk, яка підтримує регулярки, має внутрішню мову і може робити багато речей з текстом:

$ echo "c1 c2 c3" | awk '{print $2}'
c2

C) Можна навіть викусити щось регуляркою через grep — тут я беру щось між двух spacers та користуюсь можливостями grep — опція -o:

$  echo "c1 c2 c3" | grep -oP '\s\K\S*(?=\s)'
c2

Але все ці приклади використовують зовнішні команди.
Тобто операційна система повинна виділити пам’ять, ресурси, форкнути новий процес, потім завершити його та передати значення назад в скрипт.

Під Windows ця проблема ще більша, бо архітектура така, що створення нового процесу займає набагато більше ресурсів. Наприклад, в емуляції cygwin це може зайняти на два порядки довше, ніж в Linux чи навіть під Windows WSL.

Це, можливо, не має особливого значення, якщо ви робите якусь одноразову процедуру. Але якщо треба виконати команду у циклі чи це моніторинговий скрипт, що виконується кожну хвилину, то краще його оптимізувати (або навіть обрати perl/python/etc.).

D) Спробуємо розбити строку внутрішньою командою read ось так:

$ read one two three <<< "c1 c2 c3"; echo $two
c2

Для read також можна змінити сепаратор на інший символ через спеціальну змінну IFS (internal field separator) і працювати з CSV:

$ IFS=";" ; read one two three <<< "с1;с2;с3;с4" ; echo $two
c2
В останньому прикладі ми читаєм у три змінні, але маємо чотири колонки. Тому в змінну three буде записана решта значень:
$ IFS=";" ; read one two three <<< "с1;с2;с3;с4" ; echo $three
c3 c4
$ IFS=";" ; read one two three <<< "с1;с2;с3;с4;c5;c6" ; echo $one; echo $two; echo $three
c1
c2
c3 c4 c5 c6

E) Якщо у вас простий випадок, то строку можна легко конвертнути у масив:

$ myarray=($(echo "c1 c2 c3" )); echo "${myarray[1]}"
c2
Чи якщо строка у змінній, конструкція виглядає простіше:
$ string="c1 c2 c3"; myarray=($string); echo "${myarray[1]}"
c2

Індексація в shell починається з нуля. Також треба дивитись на конфлікти, якщо в елементах є спейс чи лапки, тощо.

F) Якщо у вас складний випадок неструктурованого тексту, можна використати bash variable expansion, та вирізати необхідне за декілька підходів, і навіть 5-10 variable expansion будуть працювати скоріше за один read (тут ми вирізаємо все до пробілу, потім все після пробілу:

$ A="с1 с2 с3"; b=${A#* }; echo ${b% *}
c2

Ще раз зроблю акцент на тому, що три останні варіанти працюють з внутрішніми командами Shell, тому виконуються дуже швидко. У 100-1000 разів швидше за виклик зовнішньої утиліти cut чи awk.
Нижче приблизні заміри на звичайній віртуалці (2 cpu):

time { for ((i=0;i<1000;i++)); do echo "c1 c2 c3" | cut -d " " -f 2;done }
real    0m3.537s
user    0m1.902s
sys     0m1.277s

time { for ((i=0;i<1000;i++));do read one two three<<<"с1 с2 с3"; echo $two;done }
real    0m0.163s
user    0m0.022s
sys     0m0.032s

time { for ((i=0;i<1000;i++));do  A="с1 с2 с3"; b="${A#* }"; echo "${b% *}";done }
real    0m0.061s
user    0m0.015s
sys     0m0.009s

Також зверніть увагу, що одна команда read виконувалась майже втричі довше, ніж дві команди з variable expansion.

Якщо спробувати це запустити в git-bash чи cygwin/mings під Windows, де робота з терміналом буде емульована, то все це буде на два-три порядки повільніше, та займе вже не секунди а хвилини! (За винятком WSL, бо там віртуальний Linux ;)

2. Розберемося з перенаправленнями інпуту, а саме <, << та <<<

A) Перенаправлення «<» — це перенаправлення з файлу.
Тобто Bash відкриє файл та передасть значення в команду як неіменований пайп. Це одне з найпопулярніших перенаправлень. А ще це корисно, якщо ви хочете приховати ім’я файлу. Наприклад, спробуйте виконати отак:

$ wc -l readme.txt
28 readme.txt
$ wc -l <readme.txt
28

Але в *nix також можна перенапрявляти інформацію з пристріїв, процесів, тощо. Наприклад, генеруємо рандомну строку байт:

read -N10 </dev/random
не забувайте — все є файл ;)

B) Конструкція з «<<» зветься Document Here.
Використовується, коли треба передати якийсь текст в програму, але ви не хочете створювати окремий файл для цього. Тоді ми робимо щось типу «attach» файла прямо в скрипті.

Синтаксис:

cat << EOF
ваш текст
можливо декілька строк
EOF

В цьому випадку EOF — це просто абревіатура (End Of File) для маркера початку та закінчення тексту. Ви можете використати EOF чи будь-яку іншу строку як маркер:

cat << ATTACH
ваш текст
можливо, декілька строк
ATTACH

Для тексту також виконається bash variable expansion (тобто змінні будуть замінені на значення, будуть виконані command substitutions тощо), але вам не потрібно мучитися з ескейпом лапок. Дані будуть передані, як є, що іноді дуже спрощує справу.

Приклад виконання для оракл-клієнта в скрипті:

sqlplus -s <<MYQUERY
  connect user/pass
  select 1 from dual;
  select 1 from dual;
  select "$myvariable" from dual;
  quit;
MYQUERY

Зауважу, що креденшели відкритим текстом у скрипті — це, можливо, не дуже добре.
Але так — набагато безпечніше, ніж креденшели відкритим текстом аргументами у командному рядку. Якщо просто виконати команду, то інші юзери можуть побачити пароль просто передивляючись список процесів, тому краще так не робити.:

$ sqlplus -s username/password@host:port/service @myfile.sql

C) Останнє перенаправлення «<<<».
Ця конструкція — просто передача однієї строки в команду. Приклад з тим же sqlplus:

$ sqlplus <<< "select * from dual"

Можна відправити і багаторядковий текст:

$ sqlplus <<< "select * from dual;
select * from dual;
quit;"

Але якщо вам потрібні лапки у вашому квері, то на відміну від Document Here, в даному випадку треба все екранувати.

$ sqlplus <<< "select * from dual;
select \"$myvariabe\" from dual;
quit;"

D) В каментах запропонували розглянути 2>&1

Давайте розглянемо що це, та як користуватись.
Як ми знаємо, за стандартом для процесів відкривається три хендлера 0 — stdin, 1 — stdout, 2 — stderr. Якщо будете відкривати інши, можно брати 3, 4, 5 і так далі.
Перенаправлення підтримуюсть синтаксис

1>, 1>>, 2>, 3>...
А якщо номер не вказаний, то за замовченням буде 1 (stdout).

&1 — це референс до першого хендлеру. 2>&1 — це перенаправити другий хендлер у перший. Тобто stderr в stdout. Але stderr та stdout це не destination з точку зору вже запущеного процесу, це вже відкріти хендлери кудись.
Найчастіше вони ведуть до конкретного терміналу вашої сессії, але може бути і інше. Можете напряму глянути який термінал використано для поточного процесу, наприклад отак:

ls -l /proc/$$/fd

Розберемо три приклади:
find . -name "*.txt" 2>&1
Ця команда каже, щоб перенаправити stderr в stdout, при цьому stdout нікуди не перенаправлен, і на цей момент прикріплений до нашої консолі, тому візуально нічого не зміниться, ми побачимо все виведення команди в консолі.

find . -name "*.txt" >file.log 2>&1
В даному випадку, ми перенаправили stdout в файл file.log, а потім stderr в stdout, таким чином ми просто обидва output виводи перенаправляємо в файл file.log, і це корисно що не треба двічи писати ім’я того ж самого файла.

find . -name "*.txt" 2>&1 >file.log 
Команда схожа на попередню, але на момент перенаправлення stderr в stdout, він ще не був перенаправлений у файл, а просто пов’язан за виводом консолі, тому у нас stdout піде у файл file.log, а stderr піде у консоль. До цього це буде саме як stdout, що дозволяє, наприклад, зробити отакий трюк:
find . -name "*.txt" 2>&1 >file.log | grep "errors"
Це дуже корисно, бо для символа пайп, нема можливості вказати хендлер — синтаксис на кшалт 2| чи 1| не підтримується, тому якщо треба перекинути stderr через пайп, потрібно як раз цей трюк — спочатку перенаправити його в stdout, що я іноді використовую, коли треба обробити саме вихлоп stderr.

P.S. Майже всі стандартні консольні тулзи (особливо gnu tools), коректно виводять information та error/warning повідомлення у відповідні stdout/stderr, тобто на це можно впевнено спиратися. Якщо ви девелопер та пишете консольну тулзу, то це ваша відповідальність писати std::cout чи std::cerr у конкретному випадку.

3. Простий приклад FizzBuzz та навіщо писати #!/usr/bin/env bash

#!/usr/bin/env bash
for i in {1..100}; do
   [ $((i%3)) -eq 0 ] && a[$i]="Fizz"
   [ $((i%5)) -eq 0 ] && a[$i]+="Buzz"
   printf "${a[$i]:-$i} "
done

Ми викликаємо env, яка виконує іншу програму.
Для чого це робиться?
Команда env дуже корисна, коли треба задати змінну, ім’я якої несумісне із Bash variable name convention (наприклад, env ssl.cert.name=/home/test/mycert.crt java -jar myapp.jar).

Але найголовніше, навіщо ми виконуємо bash через env — це запуск bash, який може бути десь в PATH.
В різних дистрибутивах Linux/Unix/MacOS та інше, bash може бути в /bin чи /usr/bin, чи може ще десь, тому запуск через env (який завжди /usr/bin/env) робить наш скрипт більш сумісним із різними системами.

Далі в нашому FizzBuzz, залежно від ситуації ми наповнюємо значення масиву а.
І нарешті виводимо значення масиву a, але якщо там пусто, то виводимо просто індекс i.
В Bash ми можемо виконати операцію = чи += із змінними, але у нас нема -=, /=, *=, тому що в Bash нема строгої типізації змінних. І тому всі операції повинні бути сумісними як з числовими, так і текстовими. += просто виконує конкатенацію текстових змінних, та складає числові.

4. Autocomplete

Мабуть, всі користуються автокомплітом для файлів та каталогів. Але автокомпліт працює не тільки з ними. Ще він автодоповнює імена змінних і функцій, а також аліасів. Тому, якщо ви хочете зробити собі швидкий аліас, можна підібрати ім’я таким чином, щоб його можна було швидко автодоповнити з однієї-двох літер. Наприклад, писати з uppercase-літер.

alias DEBUGLOG="tail -f $HOME/myapp/debug.log"

function DECRYPT() {
  echo '$1' | openssl enc -pass file:$HOME/secret.key -d -aes-256-cbc -a
}

Ну і не забувайте, що функції, покладені в .profile чи в .bashrc також можна визивати інтерактивно. І це непогана заміна для alias, якщо треба виконати щось більше, ніж одну-дві команди, просто пишемо

DEB<tab> чи DEC<tab>
.

5. read замість sleep

sleep дозволяє зробити невеличку паузу. Але якщо замінити його на read -t <time>, то у разі інтерактивного виконання скрипта можна скіпнути цю паузу, натиснувши enter.
А ще цікаво, що read, як і sleep, підтримують долі секунд, тобто можна read -t 0.5 чи sleep 0.2.

Ну і іноді буває потрібно запускати скрипт з дефолтними значеннями чи з кастомними — read з таймаутом дозволить почекати кастомних значень. А якщо ніхто нічого не ввів (або одразу натиснув enter з пустим значенням), то це можна перевірити та замінити пусте значення на дефолтне. І скрипт можна запускати вручну чи автоматично — він просто почекає та автоматично продовжить роботу.

6. Лапки....

На останнє, проблеми з лапками та розкриттями змінних переслідують майже всіх новачків.
Найчастіше можно побачити помилки, що маємо із пустими змінними, чи змінними, чи значення мають пробіли чи інши спеціальні символи.
Приклади:
[ $myvar == "yes" ]
Якщо $myvar пуста, то буде не false а помилка синтаксису.
Якщо у $myvar будуть пробіли — це також буде помилка синтаксису.
Правильно: [ "$myvar" == "yes" ].
Ще можно використовувати продвинутий test у bash: [[ $myvar == "yes" ]], але це несумісно з POSIX.

Розберемо роботу з файлами. Маємо файл с пробілом:

$ find .
.
./test.sh
./hello world.txt

Пробуємо передати список файлів отак:

find . | xargs echo
. ./a.sh ./hello world.txt

Виглядає непогано. Але давайте перевіримо кожний елемент:

find . | xargs -n1 echo
.
./test.sh
./hello
world.txt

Виявляється, що насправді файл з пробілом було порізано на два елементи.
Виправляємо:

find . -print0 | xargs -0 -n1 echo
.
./test.sh
./hello world.txt
Так працює, тому що find та xargs мають опції, щоб змінити сепаратор на нульовий символ.

В різних випадках треба чи використовувати лапки, чи міняти дефолтний сепаратор, чи те й інше одразу. Мабуть потрібно деякий час поексперементувати, додати додаткові логи та команди, щоб перевірити та знайти для вашого випадка найкращу конструкцію.

7. Wildcard (маски файлів)

Ще маленька дрібничка про wildcard в *NIX та Windows.
У давні-давні часи, в файловій системі FAT, ім’я файла та розширення — були окремі поля. Тому в ДОС та першіх версіях Windows, всі файли можно було знайти маскою *.*

В *NIX взагалі нема такого як росширення, є просто ім’я файла, в ньому може бути крапка чи крапки. Тому знайти всі файли — це просто *. А якщо спробувати шукати *.*, то в *NIX це файли, в яких є хоча б одна крапка.

Наразі Windows також може знайти все за маскою *, але для забезпечення обратної сумісності, *.* також буде шукати всі файли в Windows, але тільки файли в імені яких є хоча б одна крапка в *NIX.

На сьогодні все, запрошую до коментарів тих, кому цікаві деталі.

P.S. Я повністю розумію, що Bash — це просто інструмент, і, якщо треба, роблю речі на python/perl/helm. Але я вважаю, що спеціаліст повинен розбиратись в bash хоча б на середньому рівні, бо це дійсно крутий і дуже поширений інструмент.

Сподобалась стаття? Підписуйтесь на автора, щоб отримувати сповіщення про нові публікації на пошту.

👍ПодобаєтьсяСподобалось31
До обраногоВ обраному31
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

навіщо той баш можно всьо на пітоні заюзать, він вже йде на всіх лінухах у 2025 році по замовчуванню! Ви же не 2000 році живете!

баш ... по замовчуванню

точніше просто — шелл

навіщо той баш можно всьо на пітоні

більшість повсякденних команд простіше з шелл — ніж з пайтон/перл/etc.

же не 2000 році живете

і шелл скрипти 20річної давнини все ще роблять без переписування, що не скажеш про пайтон за декілька років

а еще не надо качать тонну зависимостей с дырявыми либами, и обычно для совместимости пишут под sh а не баш

1. Ні, пітон не на всіх лінуксах він йде по замовчуванню
2. Все ще зустрічається проблема з python2 vs python3, і нема ніякої гарантії, що не буде проблем с python4/python5, а Posix shell сумісний forever
3. Не всі модулі пітона встановлені по замовчуванню, а консольні gnu tools як раз надійно є в поставці
4. Для роботи з зовнішнім софтом, як враппер, баш краще, простіше і швидше, ніж пітон

Але ці питання в статті я описував..

дуже якісний контент! дякую!

в цілому непогано, можливо краще булоб просто про shell — не так вже й багато специфічних баш фіч використано

Чудова стаття.
Чудовий інструмент.

Як концепт використання Баш дуже цікаво але — як на мене у реальному житті складні баш скрипти без повноцінної документації та ретельних коментарів у скриптах майже не можна підтримувати бо кожен новий девопс що приходить на проєкт викидує половину таких скриптів та пише свої, такі ж самі але його. Нажаль.
CI/CD треба будувати з мінімумом баш скриптів ( простих або складних) але мінімумом бо інакше будь яка значна зміна процесу CI/CD виливається у багатоденне випилювання одних скриптів та додавання нових.
Стаття цікава. Побільше б такого матеріалу на Доу

Якщо ваш CI/CD все ще пов’язан з віртуалками, а не докером, то под капотом в CI/CD в багатьох випадках саме шелл скріптинг. І скрипти там не дуже складні проте могуть бути великими для інтеграції з різніми тулзами.
В ентерпрайз секторі буває таке, що компанія купляє послугу в різних аудиторських систем, купляє різні стеки (іноді це буває вимога регулятора), і щоб інтегрувати весь цей зоопарк в CI/CD — проста лапша на шеллі.

Найголовніше, що шелл досить простий, щоб і без документації в ньому можно було розібратись і щось поправити. Саме тому в нього часто лізуть без документації і роблять прості помилки...

Я пишу щось на шелл, щось на пайтоні, щось на golang. Шелл повільний, але для простой інтеграції він ДУЖЕ швидкий і всюди є із-під коробки. А ще можно довіряти тому, що скрипт на шелі буде працювати і зараз і через 5 років і через 25 років. Він дуже стабільний в цьому плані, технчіний борг майже не накопичується.

Дякую за відповідь.

Я пишу щось на шелл, щось на пайтоні, щось на golang. Шелл повільний, але для простой інтеграції він ДУЖЕ швидкий

Я досить далекий від Девопс практик хоча дещо доводилося писати самому .. ну бо більше нікому було. Баш-а ще не вивчив глибоко щоб вільно писати на ньому тож використовую повершелл ( так склалося що з ним хоч й довші команди але мені якос комфортніше з ним)
Але я не розумію для яких цілей крім пайтона ( мови що не потребує компіляції) ще можна використовувати Голанг або ішні подібні мови що потребують компіляції ?
За для яких потреб ви Голанг використовуєте де не можна просто пайтоном обійтися?? Дуже цікаво

1. скомпільований працює швидше, ніж скрипт.
2. на відміну від того ж пайтона, скомпільований бінарник не потребує встановити пайтон, ще й потрібної версії, ще й з потрібними модулями. Бінарник просто виконуєьтся.
3. golang — сучасна мова в тому плані, що там достатньо комфортних бібліотек, щоб робити прості речі на кшалт http реквестів, парсинга json, тощо. Тобто це як пайтон, але нативно компілюється.
Писав на голанг декілька грабберів для метрик, прості інтеграції. Нічого складного з точки зору кода, але просто бінарник легший у підтримці.
З пайтоном досі йде міграція в деяких дістрібутивах з другого на третій...

Круто. Дякую! Так мало подібних статей тут.

Дякую.
Технічни статті не дуже популярні, бо їх читають лише ті, в кого саме ця технологія використовується в проекті. А ось обсудити HR-ів, підтянуться усі...

Наскільки я бачу проблему ДОУ, це
1. дуже довга і непотрібна преморедація. Читачі і самі можуть проголосувати за статтю, а неможливісь опубліковати — це відпугує.
2. Нема нормального Q/A, як в StackOverflow чи toster, тобто українского контенту з питаннями та відповідями, що легко індексується — тут не створити
3. проблеми з редактором...

Ну аудіторія маленька.. на іншому ресурсі в мене така ж стаття набирає десятки а то і сотню тисяч переглядів..

tldp.org/...​/html/io-redirection.html
я бы добавил бы это в мастхев помимо команд чтоб понимать что делает 2>&1

особливо, щоб розуміти чим відрізняється «>file.log 2>&1» та «2>&1 > file.log» ? ;)

Корочше я не полінився, додав ще одну секцію у статтю, бо дійсно мастхев.

Дуже хотілося б хоча б один камент на додану секцію "

D) В каментах запропонували розглянути 2>&1

", чи нормально розжував

p.s. це такий чіт для підняття переглядів статті, але цикаво чи дійсно корисно

Bash-скрипти дуже глибоко проникли в *nix і технічно й ідеологічно, вони виросли разом з *nix, а пізніше з Linux та стандартами POSIX.

[зануда ОН]
називати bash-скриптами скріптову мову, яка росла разом із юніксами — перебор. Бо bash з’явився тільки в 1989 році, а його батько, sh від Берні — в 1978-му. Тож, краще все ж термін «shell-скріпти».

Також помилкою є вважати bash найбільш потужним інструментом в лінійці командних процесорів для *nix систем. В тей час, як дійсно є більш прості і легкі sh-based процесори типу dash, широко використовуються і більш потужні командні процесори із своїми діалектами shell-мови, як-то zsh чи ksh. Вже не кажучи про несумісні із bournie shell оболонки csh/tcsh.
[зануда ОФФ]

А стаття цікава :)

Сам такий, тому мені нескладно трохи виправити початок статті. Дякую за зауваження.

Тож, якщо є більш потужні командні процесори, чому все ще Баш такий популярний? Може є якісь фічі баш-а що й досі надають йому перевагу у користувачів?

Бо гугл випустив свій стайлгайд по програмуванню саме під баш, а не інший шелл.
А взагалі насправді башизми не скрізь сприймаються позитивно, зокрема, через перехід башу на GPLv3, що дуже боляче для ембеддеду.

Стаття не тільки про баш, а про шелл в цілому, і я гадаю, що питання також було більш про шелл скриптинг, а не саме про баш

Бо потужнісь не завжди те, що потрібно під конкретну задачу. Є ще простота сінтаксису, розповісюдженість, готові напрацювання і підтримка в різних системах, тощо, тощо.

Тому, наприклад, в початковому ембеддеді ніфіга не bash найпопулярніший, а якийсь dash або взагалі busybox із підтримкою базового сінтаксису sh.

Ваше питання нагадує: «чому досі використовують C, якщо є ***єнні java і haskel»?

Ну то що вам нагадує моє питання то не моє діло тож ваші «кукухи» вам підказали мабудь якісь асоціації. Моє питання було просте тож дякую за відповідь.

Суть не в самому bash, а в shell.

1. Це не просто мова програмування, це ще й комфортна консольна оболочка, що дозволяє автоматизувати твою работу у декілька кроків.

2. Шелл скриптинг дозволяє легко автоматизувати інтеграцію різних програм.
В інших мовах ти також можешь форкнути процес, але для шелл — це натівна поведінка, мінімум коду, повна інтеграція з операційною системою.
Тобто ДУЖЕ швидко можно написати якийсь враппер, інстал/деплой скрипт, граббер чогось, що пов’язано з файлами, процесами... звичайними речами

3. шелл скриптинг всюди є із коробки, вже готовий та стабільний на десятиріччя.

Так, суть в шелл, але назва статті всеж таки починається з «Секрети в Bash ...» що викликає додаткові питання)

Для популярності статті "

що викликає додаткові питання)

" — це добре =)

Популярність — перше звичка, друге присутність з коробки в багатьох системах. А взагалі я далеко невпевнений що йому так вже явно надають перевагу ті хто сьогодні шелли юзає. Якщо чисто скриптовка — то пишуть під shell (деякий скажімо «віртуальний» posix sh), якщо робота в терміналах — тут різноманіття доволі широке по вподобанням (включно з bash як опція серед інших).

Якщо перенаправлення та пайплайни це різні речі, то як же філософія юнікс «все є файлом»?

пайп — це символ вертикальное черти, все є файл — трошки застаріла жартівна фраза, я вважаю що малось на увазы — все є стрім, просто більшість source та destination можуть мати файловый шлях.

Ну і пайплайн це взагалі цепочка виконань різніх завдань, коли кожне наступне отримує результат виконання попереднього — це вже до сучасних ci/cd

як же філософія юнікс «все є файлом»?

Можна вручну через mkfifo розставляти пайпи, будуть більш явні файли з перенапаавленнями.
Інколи буває зручно, наприклад, коли немає можливості залогінитися на сервер під рутом напряму, але потрібно зробити повний бекап tar-ом.

> як же філософія юнікс «все є файлом»
>
вона і залишається такою значною мірою, якщо це в софті то оперують файл-дескрипторами, якщо зовні — то це файл (в неймспейс файлової системи явно — якщо створений командою mkfifo для роботи пайплайн через нього як через звичайний файл, абож неявно з «|» - вважайте що це «анонімус» пайп в цьому випадку)

ця філософія стосується того, що в posix системах майже все має файловий шлях. До API операційної системи можно звертатись звичайним файловим шляхом через /proc, /dev та іншим фічам файлових систем, на кшалт іменованих пайпів.
Саме так треба сприймати це висловлення.

я би не формулював posix ідею або суть як «майже все має файловий шлях», мета була(є) — стандартизація api (навіть якщо це стандартизація тільки для unix (like)). Тобто перше що спадає на думку відносно posix — стандартизація, перше що спадає при згадуванні unix — все є файлом (умовно). Тобто це трохи інші аспекти і цілі.

Ну «все є файл» це жартівна фраза. Якщо технічно, то все має файловий шлях. Бо якщо дивитись на тип, то там не regular file а block special, character special, directory, і так далі.
Тому можно придиратись до фрази, але «все є файл» має трохи ширшу ідею, і я не розумію навіщо обмежувати до regular file

«Все є файл» якраз навпаки — це _не_ обмежувати абстракцію файл тільки регулярними файлами. І концепт відображення в неймспейс файлової системи різних сутностей доволі зручний і зовсім не жартівний.

p.s. в plan9 його навіть розширювали (Нп відображення на /net всієї мережі і абстракцій з нею пов’язаних, нп nat в такій абстракції це просто оверлей в fs на частину того /net. Теж саме відображення абстракції window в неймспейс файлової системи, і т.д. Доволі зручно для інтуїтивного використання), тільки до того часу вже всі ресурси комьюніті пішли в *nix like тому мабуть і не взлетіло це ще більше широке застосування «все є файл».

Мені здається ми кажемо теж саме, просто різними словами.

Можливо.

Для того щоб показати що це не жартівлива фраза окрім unix навів ще plan9 (проект який значно розширював цю концепцію, і нажаль вмер з переходом буквально усіх розробників в інші компані).
Тобто якщо в лінукс максимум що додали це procfs, але не дійшли до використання нп window gui з cli в вигляді типу «mkdir /windows/mycoolapp; echo some-attrs >> /windows/mycoolapp/decoration; ...» і так відносно усього в неймспейс файлової системи — мережа, девайси, ремоут-ноди, і т.д. Тобто концепт «все є файл» може бути дуже і дуже зручним, або зручним (без дуже) у випадку unix like oses.

Я мав на увазі не концепт, а саме те, що фраза стосується слова «файл», а не самої ідеї, коли різні речі доступні через файловий шлях.
block special це не файл, але у фразі «все є файл» мається на увазі, що це типа файл.

Файл, як ресурс доступний через неймспейс файлової системи, не обов’язково має бути текстовим, чи регулярним (чи ще якоюсь дефініцію з систем де така концепція використовується тільки у вузькому для тієї ос розумінні).
Це те на чому я хотів акцентувати, а взагалі думаю розуміння як концепт файл використовується на практиці — більш менш однакове.

en.wikipedia.org/wiki/Computer_file

block special чи character special, це не file regular, якщо ми про термінологію. Незалежно від OC чи ФС, є загальне поняття, що таке звичайний файл.

en.m.wikipedia.org/wiki/Computer_file
A computer file is a resource for recording data on a computer storage device, primarily identified by its filename.

block special чи character special, це не file regular

en.m.wikipedia.org/wiki/Unix_file_types
The seven _standard Unix file types_ are regular, directory, symbolic link, FIFO special, block special, character special, and socket.

Незалежно від OC чи ФС

навіть не хочу заглиблюватись в dos/windows з їх нп devices та their names reserved words that cannot be used as folder or file names.

І це зновуж навіть без прикладів відмінностей в plan9 нп, чи специфіки різних fs.

Ну то я ж кажу. Загальний термін file зазвичай це resource for recording data
А unix file це більш вузький термін, серед яких regular файл, тобто «звичайний» — це такий як всюди, і незвичні типи, включаючи нестандартні, що може реалізувати кожен хто пише свою операційну чи файлову систему.

В windows також є типи файлів.

Соррі, але ще раз

«все є файл» це жартівна фраза
block special це не файл, але у фразі «все є файл» мається на увазі, що це типа файл

В unix:
block special — це файл (і не жартівливо, бо прописано в _стандарті_)

В unix стандартизації зазвичай посилаються на posix чи sus (нюанси в різниці між ними — за рамками цього питання)

Це posix:

3. Definitions
3.139 File
An object that can be written to, or read from, or both. A file has certain attributes, including access permissions and type. File types include regular file, character special file, block special file, FIFO special file, symbolic link, socket, and directory. Other types of files may be supported by the implementation.

(from pubs.opengroup.org/onlinepubs/9799919799)

p.s. відносно wiki: перше посилання (en.m.wikipedia.org/wiki/Computer_file) це зі статті яка потребує додаткову верифікацію (що там і відзначено), друге посилання (en.m.wikipedia.org/wiki/Unix_file_types) — верифіковане з reliable references на той же нп posix.
я розумію що тому хто звик до windows незвично бачити нп block-device file в неймспейс файлової системи як і інші файли, — тому «block special це не файл» буде misleading для тих хто на це натрапить

Ще раз. Прямо по вашому посиланню, прямо по вашим цитатам.
«block special» — це file type, тобто не загальне поняття файлу, а один з аттрибутів файла.

я розумію що тому хто звик до windows

Я працюю з *nix приблизно з 1990.

Ще раз. Не кожний файл — block special, але кожний block special — файл.
Таким чином, файл — більш ширше поняття, ніж окремі file types.

Ну я не думаю що має сенс продовжувати діалог, якщо кожен вперся в свою інтерпретацію того ж самого, що ні на що не впливає.

$ IFS=";" ; read one two three <<< “с1;с2;с3;с4” ; echo $three
c3;c4

вивело “c3 c4” через пробіл

виправив опечатку, додав ще один приклад, щоб показати що решта значень попаде в останню змінну

Поправив оформлення. Дуже сумно, що редактор на Dou працює з помилками, і редагувати складний текст — це біль.
Але можно зробити отак blabla/edit/?old та попасти в raw редактор, де все простіше.

Сергію, вітаю. Як і обговорювали з вами на пошті, дійсно можна в raw-режим ось так перемкнутись: dou.ua/forums/new/?old, а ось так для редагування: dou.ua/...​ums/topic/51355/edit/?old.

Поки що ца стаття в мене чемпіон по зірочкам. Хоча в довоєнні роки переглядів було б гораздо більше (

Будемо чекати ваші наступні матеріали! І дякуємо, що ви з DOU, а зірочок дійсно багато 🤩

Дякую за статтю. Напишіть про те, коли варто і не варто використовувати баш

Ну так складно сказати.

Для мене робити на баш простіше, коли треба працювати с не дуже організованими даними, і я не можу просто взяти та конвертнути в масив. В шелл скриптах можно використати декілька операцій через awk та конвертнути в потрібний формат. Але в pyton бібліотека дозволяє простіше обробляти помилки.

Чи треба поєднати декілька тулзів — це взагалі найперше. Наприклад обнулити базу даних (якийсь sqlplus квері чи на тестовому енвайрнменті відновити свіжий бекап, щоб відкатити до ініціалізованого стану), потім запустити якись тести, потім відправити це через пошту. Тут баш сам себе кличе.

Чи треба щось зробити в init контейнері — підготувати сертифікати чи секрети, встановити права доступу та інше.

Тобто дуже багато дрібного клею, на якому я звик в баш робити речі простіше для себе. Зараз в мене навіть телеграм бот на баш є, з різними штуками, вміє малювати карти, грати в шахи.
Ось картинка на початку статті — це як раз код для консольного bс, який обчислює дистанцію між двома координатами, що можно получити через googlemap api, а так як земля не плоска, то для розрахунків дистанціі між координатами (довгота та широта) треба трохи заморочитись.

Чесно кажучи, очікував чергової статті для початківців з прикладами cd, ls, touch/mkdir, але дуже приємно здивований крутими фішками. Автору — респект. Пиши ще)

Це значно краще ніж «виправлення» хоум брю

Я мабуть не в темі, з чим ви порівняли?

ну да, там неясно чому apt-get не підійшов

там неясно чому apt-get не підійшов

Там насправді все ясно: тому що пакетний менеджер apt не використовується в MacOS, там якраз Homebrew найпопулярніший. А apt-get нехай залишимо дебіаноподібним дистрибутивам.

Більш очікуваним було б побачити в macos щось з bsd бінарних пакадж менеджерів (pkg з freebsd, pkgin з netbsd, ...), але навіщо якщо там вже є homebrew. Це булоб те саме як пропонувати нп використовувати homebrew замість apt в debian-derived системах.

Підписатись на коментарі