LINUX.ORG.RU

А какие сейчас есть актуальные замены (da|ba|k|)sh для скриптов?

 , скриптинг


1

4

Пишу сейчас очередной sh-скрипт с кучей вызовов awk, grep и sed. В связи с чем задумался об альтернативах. Попытался сформировать список черт, которые делают sh до сих пор актуальным инструментом:

  • Возможность легко и просто скомпилировать под любой утюг.
  • Отсутствие развесистой библиотеки, которую интерпретатор таскает с собой, а также как следствие — нет слома совместимости между версиями библиотеки.
  • Минимальное время инициализации интерпретатора.
  • Малое потребление памяти.
  • Простой параллелизм через fork.
  • Возможность удобно и просто вызывать внешние команды и пайплайны команд.
  • Возможность прозрачно миксовать внешние команды и собственные функции. (В sh мы делаем command1 | command2, и это работает одинаково, независимо от того, являются ли эти команды собственными функциями или внешними командами.)

Если обобщить, то главным отличием sh от ЯП типа perl, ruby, python и т.п. является композиция программы как совокупности исполняемых модулей, запускаемых как отдельные процессы, в противовес композиции библиотечных модулей, слинкованных в единый процесс.

Главным минусом sh является то, что в нём не развиты средства работы с какими-либо структурами данных, кроме строк. Да и для самих строк средства не развиты.

То есть потециальная альтернатива sh должна обладать всем перечнем указанных черт, но дополнительно иметь развитые средства работы со структурами данных такими как списки, хэш-массивы и т.д.

★★

Последнее исправление: wandrien (всего исправлений: 5)
Ответ на: комментарий от wandrien

Брать крайне легковесный ЯП общего назначения, чтобы время инициализации интерпретатора снова стало дешевым. Выше предложили вариант с Lua.

он как бы куцый, неполноценный. можно пожелать чего-то вроде счастливой отладки, а питон есть везде, главное ориентироваться на версию питона 3.6.5 или 3.5.4 (в линетере настроить проверку синтаксиса, ориентируясь на данные версии), те без асинхронщины и тайп-хинтов.

можешь взять go, написать на нем свою чудо-программу, скомпилировать ее с флагом CGO_ENABLED=0, и тогда она гарантирована будет запускаться даже на centos, который не обновлялся с 2010-х

rtxtxtrx ★★
()
Ответ на: комментарий от wandrien

А это все точно надо оптимизировать? Минимизировать надо время-разработки + время-исполнения, и то не минимизировать а обеспечивать условия что бы эта суммарное время было приемлемым.

AntonI ★★★★★
()
Ответ на: комментарий от AntonI

А ты думаешь, выписывание многоэтажных sed – это не лишние затраты на время разработки? Как раз они.

А потом еще оказывается, что в интерактивном скрипте, который должен укладываться в комфортное время отклика UI, есть задержка в треть секунды из-за полсотни лишних fork-exec. И приходится переписывать весь кусок либо средствами самого sh, что не всегда возможно, либо в один комплексный вызов awk, то есть по сути менять всю реализацию этого куска алгоритма.

wandrien ★★
() автор топика
Последнее исправление: wandrien (всего исправлений: 1)
Ответ на: комментарий от wandrien

Ну это можно. Массаракш с языка планеты Саракш переводится как мир наизнанку - кто не читал «Обитаемый остров», у них там из за рефракции атмосферы визуально горизонт задирался наверх и преобладала теория вогнутой земли.

Соответственно ЯП массаракш должен выворачивать наизнанку все общепринятые парадигдмы программирования. Т.е. точка входа в функцию это return, все объявленные в функции переменные глобальные а глобальные переменные на самом деле локальные, и т.д.;-)

AntonI ★★★★★
()
Ответ на: комментарий от wandrien

А ты думаешь, выписывание многоэтажных sed – это не лишние затраты на время разработки? Как раз они.

А потом еще оказывается, что в интерактивном скрипте, который должен укладываться в комфортное время отклика UI, есть задержка в треть секунды из-за полсотни лишних fork-exec. И приходится переписывать весь кусок либо средствами самого sh, что не всегда возможно, либо в один комплексный вызов awk, то есть по сути менять всю реализацию этого куска алгоритма.

Не сочти за троллинг, но зачем всем этим страдать? Можно же тупо взять и написать все на питоне/go/whatever без sed, awk и прочего?

goingUp ★★★★★
()
Ответ на: комментарий от Shadow
import re

# убираем `\n` и `\r\n` в конце
for line in map(str.rstrip, open("file.txt")):
  # начинается с подстроки
  if line.startswith("abc"):
    print(line)
  
  # содержит подстроку
  if "abc" in line:
    print(line)
 
  # начинается с шаблона
  if re.match(r'[ \t]*The', line, re.I):
    print(line)

  # содержит шаблон
  if re.search(r'\b(cat|dog)\b', line, re.I):
    print(line)


# awk
import csv
with open("products.csv") as fp:
  it = csv.reader(fp)
  next(it) # пропускаем заголовки
  for row in it:
    if row[3] == "whtaever":
      print("adatfzhga")
rtxtxtrx ★★
()
Последнее исправление: rtxtxtrx (всего исправлений: 2)

Вспомнил про https://github.com/neurobin/shc.

A generic shell script compiler. Shc takes a script, which is specified on the command line and produces C source code. The generated source code is then compiled and linked to produce a stripped binary executable.

The compiled binary will still be dependent on the shell specified in the first line of the shell code (i.e shebang) (i.e. #!/bin/sh), thus shc does not create completely independent binaries.

shc itself is not a compiler such as cc, it rather encodes and encrypts a shell script and generates C source code with the added expiration capability. It then uses the system compiler to compile a stripped binary which behaves exactly like the original script. Upon execution, the compiled binary will decrypt and execute the code with the shell -c option.


expiration capability

😄

dataman ★★★★★
()
Ответ на: комментарий от wandrien

Тут ещё тонкий психологический момент — переформатировать собственное восприятие под новый инструмент.

Вот например, для какой цели сейчас используется fork? Если что, «дешёвый» он только по сравнению с созданием нового процесса с нуля. А по сравнению с вызовом сишной функции/созданием треда/etc. — ни разу не дешевый.

И в достаточно развитых языках (даже минималистичном Lua) параллелизм и раздельные контексты достигаются иными средствами. А использование форков возможно потребует ещё и вагон костылей, чтобы всё не превратилось в хитросплетение гейзенбагов.

anonymous
()

Мне тут как раз тоже нужно писать скрипты для одного ответственного дела, и ситуация такая, что вот есть шелл на одном полюсе, и есть полновесные ЯП (в которых все базовые структуры данных, и развитые средства для работы с ними и т.д. и т.п. и далее по списку, да ещё и всякая статическая типизация). И вот как бы удачно скрестить их никому не удалось. Для себя решил так: как можно дольше использую bash. Если начинается дроч с «кучей вызовов awk, grep и sed» и код наачинает выглядеть слишком громоздко, или вообще появляется мысль «не буду это на шелле реализовывать», беру питон, но не переписываю всю задачу на нём, а только ту часть, которую сложно делать на баше.

При этом желание «Возможность легко и просто скомпилировать под любой утюг.» - в реальности оно редко нужно, это как «комп на вырост» покупать - переплачиваешь за то, что тебе никогда не понадобится. В реальности у меня целевая платформа - полновесный дистр Линукса на обычном ПК, и максимум, что теоретически может понадобиться - чтобы работало на винде, да и то никто пока не требует, так что фактически платформа одна.

seiken ★★★★★
()
Ответ на: комментарий от anonymous

Например, при длинной обработке цепочки текстовых данных или всяким там поискам по файловой системе, в привычном императивном ЯП ты скорее всего не будешь думать, «как это распараллелить», потому что на это нужно тратить дополнительные усилия. Ты просто реализуешь последовательный алгоритм.

Запустив пайплайн из готовых компонент, каждый из которых оптимизирован под задачу, ты получаешь эту оптимизацию бесплатно.

Она будет не такой эффективной, как если бы ты запрограммировал всю параллелизацию вручную. Но зато ты на неё и усилий не потратил.

wandrien ★★
() автор топика
Ответ на: комментарий от rtxtxtrx

Суть в том, что Ruby как идейный последователь Perl-а очень заморочен на тему того, чтобы писать «красиво и лаконично».

Например, загугли, что такое ARGF. Эти 4 буквы тебе сэкономят с десяток или больше строк однотипного бойлерплейта в каждой тулзе, которую ты будешь писать для обработки текстового потока данных.

К сожалению, обратной стороной медали является очень долгая инициализация интерпретатора. Что ссылка выше на тесты и подтверждает.

wandrien ★★
() автор топика
Ответ на: комментарий от wandrien

К сожалению, обратной стороной медали является очень долгая инициализация интерпретатора

Так это не важно. Интерпретатор баша раз в 300 медленее (но это не точно).

rtxtxtrx ★★
()
Ответ на: комментарий от AntonI

Строки эти новые питонячьи я люто ненавижу потому шта появились еще bytes и иногда одно в другое надо гонять а то не работает.

Главное - при переходе от py2 к py3 они сломали обратную совместимость, но при этом не решили ни одной родовой травмы питона вроде разделения на изменяемые/неизменяемые объекты.

Да, недавно как раз натыкался на программу на Python 2 где активно использовались строки как хранилище байтов с последующим байтодрочем и всякими ord(), chr(), вычислениями чексумм. Портировать на Python 3 с наскока не получилось, пришлось разбираться и всё переписывать с нуля.

Очень жаль, что взлетел именно Python в плане популярности и батареек, с его наплевательским отношением по части обратной совместимости.

Излом Python 2 => Python 3 это позор экосистемы Python. Решение которое замусорило дистрибутивы и создало огромную кучу проблем на ровном месте.

EXL ★★★★★
()
Ответ на: комментарий от anonymous

Тоже что-то такое делал на коленке, луа и перл приятно удивили, а питон ожидаемо раз в 30 медленнее стартовал. Туда бы ещё всяких лиспов, тикль и гуиле для полноты картины.

fumanchez
()
Ответ на: комментарий от rtxtxtrx

Эмм… нет?

Если что, Ruby красивый, объектно–ориентированный, приятный в написании, лаконичный, с кучей батареек в комплекте, но о–о–о–о–о–о–чень тор–моз–но–о–о–ой. Даже тормознее п(и|ай)тона.

anonymous
()
Ответ на: комментарий от wandrien

https://github.com/elves/elvish

Languages: Go 86.9%

Поставлю, пощупаю.

Вообще тенденция какая-то.

Если я встречаю какую-то ранее неизвестную мне тулзу на Go, то скорее всего это окажется продуманная и полезная штука.

Если я встречаю новую тулзу на Rust, то скорее всего это будет невнятная оверинженернутая хреновина.

Из исключений вспоминается разве что fd.

wandrien ★★
() автор топика
Ответ на: комментарий от wandrien
input.c:279:1: error: conflicting types for ‘getenv’; have ‘char *(char *)’
  279 | getenv(char *name)
      | ^~~~~~
In file included from stdenv.h:94,
                 from es.h:4,
                 from input.c:4:
/usr/include/stdlib.h:773:14: note: previous declaration of ‘getenv’ with type ‘char *(const char *)’
  773 | extern char *getenv (const char *__name) __THROW __nonnull ((1)) __wur;
      |              ^~~~~~
dataman ★★★★★
()
Ответ на: комментарий от wandrien

Поставлю, пощупаю.

$ pacman -Qql elvish | grep '[^/]$'
/usr/bin/elvish
/usr/share/doc/elvish/0.20.0-release-notes.md
/usr/share/doc/elvish/CONTRIBUTING.md
/usr/share/doc/elvish/PACKAGING.md
/usr/share/doc/elvish/README.md
/usr/share/doc/elvish/SECURITY.md
/usr/share/licenses/elvish/LICENSE

Документацию в пакет не завезли. Оптимистичные ребята собирали пакет.

В Арче поставляется как бинарь с зависимостью от libc:

$ ldd /usr/bin/elvish 
	linux-vdso.so.1 (0x000075b38d901000)
	libresolv.so.2 => /usr/lib/libresolv.so.2 (0x000075b38d89d000)
	libc.so.6 => /usr/lib/libc.so.6 (0x000075b38cc14000)
	/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x000075b38d903000)
$ ls -lh /usr/bin/elvish 
-rwxr-xr-x 1 root root 9,0M мар 18 19:55 /usr/bin/elvish

На официальном сайте поставляется как полностью статический бинарь:

$ ldd elvish-v0.20.1
	не является динамическим исполняемым файлом
Status: 1
$ ls -lh elvish-v0.20.1
-rwxr-xr-x 1 vadim vadim 9,6M янв  1  2000 elvish-v0.20.1

Дата бинаря выставлена на 2000-01-01. Авторы на что-то намекают, хз на что.)

wandrien ★★
() автор топика
Последнее исправление: wandrien (всего исправлений: 1)