Pull to refresh

Comments 133

Однострочники на шеле — ад. Они хороши, когда по быстрому нужно сделать одно (несколько) простое действие с лёгкой логикой. Заниматься обработкой структурированных данных в однострочниках — плохая идея. Для этого можно открыть любимый REPL и сделать в нём всё тоже самое.
Однострочники — это оригинальный смысл слова «программирование». То есть не отлитие в чугуне продакшен кода на века вечные. Однострочник, это чтобы сделать _сейчас_.

Мне сейчас нужно получить список процессов, с которыми я там что-то сделать хочу.

И «обработка» подразумевает _сейчас_. Чтобы получить ответ. Их смысл примерно такой же, как у формулы снизу таблицы в excel'е — это прямое указание компьютеру «поди и сделай». И это указание быстро пишется и быстро выполняется. Без длительных import, prelude, расписания модели классов и т.д.

В каком-то смысле однострочник — это «программа» масштаба программы для программируемого калькулятора. Она делает только то, что надо делать и не делает ничего другого (в том числе того, что хотелось бы для упрощения отладки/сопровождения).

Переиспользуемые однострочники — это уже спорный вопрос (если он переиспользуется — не переписать ли его как нормальную программу?). Но вот в режиме «ща посмотрю» или «ща сделаю» — у них просто нет альтернатив.
>И это указание быстро пишется и быстро выполняется. Без длительных import, prelude, расписания модели классов и т.д.

То, что мир потерял с уходом Бейсика. И то, на чём в своё время Бейсик набрал популярность. Там программу можно было писать с первой же строчки.
Очень много скриптовых языков целятся в эту же нишу, от JS до Python
И нескриптовых тоже, например, F#
С каких это пор несколько пайпов стали адом?
Несколько пайпов — норм, я имел ввиду ситуации когда этими однострочниками начинают делать какие-то не тривиальные вещи, вроде парсинга html-я, json и т. п.
Погодите. Мне не нравится future continuous у вас в словах.

Если кому-то надо быстро выдрать из html'ки нужные данные и он их выдирает — никаких проблем. Кто быстрее, того и тапки.

А вот если он его куда-нибудь стационарно прописывает «а вот тут мы по крону делаем вот такой трюк, и наш сайт объявлений работает» — то это уже совершенно другой разговор, и за такое (если это не прототип из г-на и палок) надо больно бить по рукам, за диверсию в отделе сопровождения.

Пайпы и однострочники — это инструментарий системных администраторов и похожих на них пользователей. И у него масса проблем, но это проблемы «иногда неудобно», а альтернативой им является «никак нельзя за 5 минут это сделать».
Задачки вроде взять список процессов и посчитать, сколько памяти съели некоторые из них — это одно. Для таких шел и пайпы — самый естественный способ. Задачка сходить по http за html-кой, вытащить из неё какие-либо данные, чёто с ними поделать, сформировать json-чик а затем положить в mysql — лучше всё же решать на скриптовых языках врод python/perl/etc.
Когда находишь для себя новый прикольный инструмент — хочется начать решать им все задачи. В IT очень много тьюринг-полных штук, а значит почти любой инструмент можно заставить решать почти любую задачу, но это не всегда целесообразно.
Предметная область не важна. Важно то, как оно используется. Если это однократная операция, то однострочник будет быстрее в разработке, чем любой другой вид программирования. Сам однострочник может быть и перловым, если кому-то привычнее.

Это tradeoff между скоростью написания и удобством сопровождения. Если мы можем полностью пожертвовать сопровождением, то можем значительно выиграть в скорости написания.

Если же получившийся код начинают сопровождать, что кратковременная экономия на времени написания оборачивается длинной попоболью в сопровождении.
Вообще, идея очень хорошая.

app-specific утилиты, наверное, стоит спрятать в одну утилиту-враппер: json-src ls -la, json-src ps ax и так далее. Под капотом у неё будут отдельные плагины для работы с конкретными командами в конкретных средах.

(я бы на go писал:))
Плагины меня смущают, потому что юникс-принцип — каждая утилита делает только одно дело, но очень хорошо. (На самом деле всем понятно, что это будет пачка симлинков на одну и ту же программу, но с точки зрения пользователя они должны выглядеть как разные программы).

Если готовы осилить — будет вам искренняя благодарность. А go, то есть быстрые бинарники — так, вообще супер.
Предложенный подход лучше описанного в статье не потому, что плагины, а потому, что вывод команд очень сильно зависит от параметров. Поэтому написать утилиту ps2json вызываемую в конвейере после ps будет намного сложнее, чем утилиту которая сама вызывает ps, зная с какими параметрами она его вызывает и в каком формате ей ожидать результаты.
В соседнем треде обсудили и решили, что лучше иметь jps, jls и т.д., из-за проблем с парсингом. В принципе, это не отменяет input'ов от произвольных утилит, но json-версии для генерирующих coreutils/procutils — надо. (ls, find, ps, free, who, last, df, du, etc)
Ну, учитывая что вариантов разных реализаций ls/ps полно, и чем делать парсинг их вывода (со всеми возможными вариантами и самих утилит и их ключей) проще повторно реализовать их функциональность в рамках jls/jps — мы приходим к тому, что нужен не парсер из pipe в json, а отдельные «командлеты» как в powershell. Далее, если мы захотим чтобы эти новые команды были совместимы по параметрам со своими базовыми командами, выяснится, что как минимум половина параметров стандартных команд отвечает за то, какие данные выводить и как их форматировать — что при выводе в json теряет смысл т.к. проще сразу вывести все возможные данные (а для отбора нужных полей, сортировки, группировки и финального форматирования удобнее будет использовать специальные json-утилиты).
Тут не должно быть противопоставления. jls/jps и остальное, что захотите, да. Но при этом они являются лишь простейшими утилитами, которые не являются частью systemd гигантского монстрообразного фреймворка. Если спросить, что делает jls, ответ будет — выводит список файлов в json'е. Без каких-либо фреймворков, командлетов чего-либо.

То есть я старательно любуюсь идеей самостоятельных утилит, каждая из которых делает одно, но хорошо, а вы меня пытаетесь убедить, что это то же самое, что команды в гигантском фреймворке, построенном на совершенно необъятном титаническом гига-мега-фреймворке. А я вам не верю.

Ну, не то, чтобы действительно пытаюсь. На самом деле у меня крайне поверхностное представление о PowerShell и командлетах, сам я им не пользовался, только читал про него и смотрел примеры. И мне не понравилось. Ну т.е. это реально лучше стандартной виндовой командной строки, но по-моему зря они через пайпы решили гонять объекты — это слишком сложно и наворочено. Так что я не пытаюсь Вас убедить, я просто высказываю относительно обоснованное опасение, что двигаясь в эту сторону Вы можете прийти к чему-то вроде PowerShell, со всеми его недостатками в виде использования своих собственных команд вместо штатных утилит и довольно сложными операциями над (так же довольно сложными) данными передаваемыми через конвейеры. И необходимостью знать все эти новые команды и данные чтобы им пользоваться.
Powershell может использовать штатные утилиты (см ниже пример с Grep). Объекты это проще для использования, потому, что не надо ни на передающей стороне ни на принимающей определять формат данных — есть уже готовое соглашение. И перечень свойства тоже не обязательно явно указывать, если его не надо выводить.

пример (вывод 10 последних созданных файлов в CSV):

ls | sort CreationTime -Descending | select -First 10 | epcsv c:\test.csv

ls по умолчанию вообще не выводит CreationTime, но, тем не менее, я могу использовать это свойство. Мне никак не надо заботиться о формате данных (объяснять ls, что нужно дальше по пайпу).

Не самый удачный пример — когда сравниваешь это с ls -t | head как-то не возникает восхищения объектами в пайпах.
восхищения не возникает из за захардкоженности сортировки в ls или из за того, что вывод в csv проигнорирован? :)
Вы не поверите, но… ни разу за 20 лет работы в командной строке линуха мне не требовалось сохранять результат конвейера в csv. Поэтому и проигнорирован.
А мне периодически это бывает удобно. Как бы вы сделали такое на вашем шелле?
Ну, с учётом того, что мне это никогда не было нужно, и я не знаю существующих утилит которые бы это делали, то я бы это сделал в лоб ручками (для примера создадим файл с именем, которое нужно экранировать в csv):
touch 'a  ,  b  "  c'
ls -ltQ | head -n 6 | tail -n 5 |
  perl -pe '$_=join",",split" ",$_,9;s/\\"/""/g'
-rw-r--r--,1,powerman,powerman,0,июн,2,18:21,"a  ,  b  ""  c"
drwx------,3,powerman,powerman,4096,июн,2,17:53,"Mail"
drwxr-xr-x,12,powerman,powerman,4096,июн,2,17:44,"download"
drwx------,9,powerman,powerman,4096,июн,2,07:09,"doc"
drwxr-xr-x,18,powerman,powerman,4096,май,30,14:21,"tmp"
Наверняка существуют утилиты (или хотя бы модули для перла) использование которых сделало бы эту команду короче и читабельнее. Но в ситуации когда один раз за 20 лет понадобилось вывести список файлов в csv — сойдёт и такое.
А, я вижу, что вы используете знание о том, что колонка с именем последняя, а в остальных не может быт разделителя.

Ну как бы оно не было сделано, пока нет четкого соглашения о форматах надо каждый раз раскорячиваться — разбирать и собирать и для интересных колонок определять формат. Либо нагружать каждую конкретную команду еще и командами обработки — как например ls содержит себе sort, но только по выделенным атрибутам.
А теперь попробуйте вырезать из этого файлы с 5 по 10 и вывести только пару файл — атрибуты.
Не совсем понимаю, что это покажет, и о каких конкретно атрибутах речь, но в любом случае это не проблема:
ls -t | head | tail -n 5 | xargs -i stat -c '%A %n' {}
-rw------- mbox3
-rw------- mbox2
-rw------- mbox1
-rw------- postponed
drwxr-xr-x VirtualBox VMs
Добавьте символы табуляции и перевода строки к имени файла и повторите тест.
А вот честно, лично Вам хоть раз в жизни попадались эти символы в именах файлов? Кроме того, баги есть абсолютно в любом софте, почему в этом онлайнере их не должно быть вообще?
Табы и пробелы — постоянно. А ещё япоцы любят в неюникодных архивах отжечь по-чёрному с именами файлов.
Никогда не встречал табов в именах файлов (кроме тех случаев, когда сам их вставлял для тестирования). Как они туда вообще попадают? В командной строке никто такое делать в здравом уме не будет. В гуи таб обычно при всём желании в имя файла не вставишь т.к. нажатие таб переключит фокус с поля ввода имени файла на следующий контрол. Так откуда в именах Ваших файлов табы?
Распаковал архив.
Проблема JSON в том, что нет нормального стандарта по его валидации. Есть несколько подходов к валидации наподобие json-schema.org/, но они не являются официально одобренными стандартами, а, значит, не выглядят совсем «серьезными», как, например, XSD или XSLT. С другой стороны XML не так удобен, если им оперировать в одну строчку. Но как насчет такой связки: утилита | инструмент генератор XML | xsltproc? Можно написать набор XSL преобразований, которые реализуют те же возможности, что и предлагаемые вами.
То есть вы предлагаете пользователю писать xsl? Просто для осознания масштаба проблемы: мне надо взять список из одного места, отфильтровать его, взять одно поле из оставшегося, и к этому применить программу.

Сколько сотен кнопок надо будет посвятить злому божеству XML, чтобы это описать на XSL? Вопрос исключительно и только в эргономике.

Валидацию json'а можно делать методом «не грузится в используемую библиотеку». CS-фрики будут плакать, остальных это устроит.
По сути вы говорите о аналоге XSL для JSON, вот вам и пишут что недостаток JSON-а в том, что нет для него XSL и даже XPATH. Был бы хоть XPATH для JSON — не было б проблем.

P.S. Кстати, всякие самописные JSONPath существуют — goessner.net/articles/JsonPath/
Может ваша задача решается запуском JSONPath из консоли? Для того, чтоб «отфильтровать список» (т.е. выбрать элементы, соответствующие сложному условию) — самое оно. И «взять одно поле из оставшегося» — аналогично.
Мы смотрим на это с разных точек зрения. Вы с точки зрения «стационарного программиста». Который код пишет меньше, чем этот код потом работает. В таком случае написание преобразования вполне оправдано.

Я же говорю про стыкуемость деталек для одноразового калейдоскопа. Если там хотя бы штук 50-80 кнопок на преобразование, это мертворождённый проект. Вне зависимости от архитектурной красоты.

Возможно, я не до конца понимаю, как xsl будет выглядеть, если покажете общественности, буду благодарен.

На входе — xml с именованными полями для каждого объекта в перечислении, надо по полю «name» отфильтровать тех, кто foo.+bar, а потом вывести только поле «display».
Для вашего случая достаточно одного XPath выражения — это гораздо короче чем полноценная XSLT.

Опять же, смотрите в сторону JSONPath (выше по ссылке примеры результатов есть) и возможности запустить его из терминала.

Я вот какраз нагуглил и пытаюсь запустить такое — search.cpan.org/~sharyanto/App-jpath-0.03/bin/jpath
Вроде пошло.
Я не понимаю ничего в Перле, но вроде как:
cpan App::jpath
инсталирует jpath как комманд-лайновую утилиту.

А дальше все просто:
cat test.json | jpath "$.store.book..title"

Для такого test.json:
test.json
{ "store": {
    "book": [
      { "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      { "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      { "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      { "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}



Возвращает названия книжек. Правда в формате JSON массива тоже.
[
   "Sayings of the Century",
   "Sword of Honour",
   "Moby Dick",
   "The Lord of the Rings"
]
А греп в середине?
Должно работать с условиями, там в примерах есть:
$..book[?(@.price<10)]
Выбор всех книжек дешевле 10.

Правда в той версии которую мне поставил cpan это почему-то валится с ошибкой. Но видимо надо просто как-то скомпилить новую из сорсов с github.

Почитайте про XPath и условия в нем. Здесь все должно быть аналогично.

На худой конец можно попробовать вообще превращать JSON в XML, проганять XPath, и потом результат обратно конвертировать в JSON при надобности.
Да, выглядит терпимо. Но я xpath не очень люблю, хотя, json-версия может быть полезна. В принципе, в рамках описываемой модели, как один из инструментов (для тех, кому надо и не лениво) — why not?
Посмотрите еще на XQuery. Там вообще полный turing complete с весьма навернутыми запросами а ля SQL — группировки, окна, вот это все.

Единственный недостаток — длинноватый синтаксис для «повышенной читабельности». Но при этом куда более лаконичный XPath является чистым subset, поэтому можно пользоваться в основном им, а FLWOR оставить для сильно навернутых запросов, где эта читабельность реально имеет смысл.

С другой стороны, сам XML как формат явно избыточнен для таких целей, а вот JSON — самое оно.
Я скорее имел в виду наделать готовых XSL-файлов и распространять в виде библиотеки.
Ага. Ну свои выражения писать — полюбому гибче будет.
Как несколько утилит (j2x для конвертации в xml, x2j обратно, и что-то посредине) — почему бы и нет? Основные тезисы: пользователь не должен видеть потрохи. xml там, json или что-то ещё — не важно. Пользователь данные всунул, написал/использовал логичный фильтр (логику которого можно понять без взгляда на xml), пользователь получил данные.
Да, я его видел. К сожалению, не полностью то, что нужно.
Спасибо, посмотрю.
Идея хорошая, но вот json — он все таки не «потоковый» формат, может быть yml здесь подолшел бы лучше? С другой стороны — если операции над json объектом, то может быть не получив объект целиком нельзя им оперировать?
grep тоже не потоковый. Ему хочется строчку целиком, а не поток байтов. Однако, для практических целей это не важно (а более злую буфферизацию приходится отключать с помощью --line-buffered).

Я думаю, имея на руках объект верхнего уровня, легко понять что ждать дальше. Если это object, то ждём следующего key+value, если это array, то элемента.

Хотя да, вопрос интересный. Потоковость туда придётся утрамбовывать силком.
Зачем на верхнем уровне все запихивать в один array?
Общепринятный формат вывода многих юниксовых утилит — «одна строка — один объект».
Его и стоит придерживаться, только формат отдельных строк сделать json вместо каши из произвольных разделителей.
То есть, выводить список объектов по одному на строке, разделять \n, заканчивать EOF, \n в значениях полей эскейпить.

Бонусы:
1. Итерация по строкам тривиально реализуется во всех языках программирования, без специальных json-парсеров
2. Стандартные head, tail, uniq и прочие работают из коробки как надо, даже не зная, что в строках json
3. Человекочитаемо даже без специального pretty-print
4. Это никак не ограничивает возможность создания вложенных списков или принудительного представления вывода одним array, если ну очень хочется.
То есть вы предлагаете использовать стопку json'ов вместо одного ч массивом? Спасибо за идею, буду думать/сравнивать.
Согласен с zibada. Т.к команды в шелле при использовании пайпов запускаются параллельно, они между собой передают по одной строке, содержащей JSON. Это позволяет не напрягать одну команду в один момент времени всем результатом, а прогонять «по-объектово».
Чем YAML более потоковый чем JSON?
Вероятно имелось в виду, что в большинстве случаев данные в YAML будут содержать по одному значению в одной строке и без всяких скобочек открывающих/закрывающих списки и объекты — что может дать возможность удобно обрабатывать его даже стандартными утилитами grep/sed/etc… Но на практике YAML значительно сложнее JSON, и там есть и свои многострочные значения, и скобочки.

Впрочем, с ходу я бы эту идею отметать тоже не стал — ведь в большинстве случаев YAML таки будет простым, и обработка его стандартными grep/sed/etc. будет подвержена ошибкам из-за не учтённых нюансов в формате входных данных не более, чем она подвержена этому сейчас, когда парсит вывод ps/ls напрямую.
>>При этом есть враждебная и не очень хорошо написанная среда — powershell (винды). В которых взяли хорошую идею (пайпы передают не текст, а объекты), но испортили её двумя вещами:

>>1.Неэргономичной консолью виндов (Shift-PgUp где, а?)

Можно ли узнать что делает эта комбинация? По быстрому не смог найти.

>>2.предложением пойти и выучить .net для того, чтобы нормально с методами работать.

Я так понял, что при использовании json нельзя вообще вызывать методы так как передаются только данные без поведения. Можно ли узнать чем json лучше в этом аспекте Powershell.

В предыдущих спорах по поводу шеллов мне говорили что уже есть объектный шелл — ipython — рассматривали ли вы его?
Shift-PgUp/Dn мотает консоль на экран вверх/вниз. Быстрый метод увидеть history за пределами экрана. В виндах для этого приходится тянуться к мышке. (Приходилось по состоянию на 2008 год, как сейчас — не знаю).

json в этом случае проще. То есть охватываемо и изучаемо. .net для целей системного администрирования — это примерно как «эрланг для целей написания конфигов», то есть смещение POV с удобства пользователей на удобство разработчиков системы.

ipython я юзаю, к сожалению, там такого сделать нельзя:
In [5]: for a in `ls /`:
...: print a
...:
File "<ipython-input-5-a746a2e08210>", line 1
for a in `ls /`:
^
SyntaxError: invalid syntax

То есть совместить удобно шелл и обработку данных не получается. Если бы было можно — было бы здорово.
В powershell ISE это комбинация Ctrl + PgUp

«json в этом случае проще» в powershell можно ограничиться изучением свойств, а методы не учить. Весь дотнет можно не учить — только то, что требуется в данный момент. То есть эта сложность получится по требованию.

ipy я не юзаю, но суда по карточке, там можно это сделать, но системный команды предвараются!
damontallen.github.io/IPython-quick-ref-sheets/
типа files = !ls /usr
Ага, значит, что-то прикрутили.

Вариант «вечно доучивать» меня не устраивает. Да и как жить с внешним миром не понятно — power she'll на себе замкнут, с выводом из перлового скрипта и отправкой в awk его штатно не заюзать. Или, там, с grep'ом посреди pipe'а.
Так работает ls | grep ".exe" | echo

ls и echo — alias-ы ps, grep — из msys
Ок, мне надо взять список открытых fd из /proc. Как мне это сделать? Допустим, центось. Или дебиан.
Это уже совершенно другая претензия — Powershell есть только на винде.

Можно попробовать sourceforge.net/projects/pash/ но я бы не стал :)
То есть если бы оно было кросс-платформенное (и не такое адское, как mono), то я бы его ещё мог рассматривать. Но я с трудом себе представляю боевой сервер, на котором ставят mono только ради пайпов в шелле у админа.
>>Вариант «вечно доучивать» меня не устраивает.

Мне кажется вам в любом случае придется хоть что-то вечно доучивать — новые команды форматы экзешников и др В случае с powershell просто есть уже готовый протокол, который уже проталкивается вендором и поддерживается в своих продуктах.

>>Или, там, с grep'ом посреди pipe'а

Это еще почему?

Get-ChildItem | grep exe | ogv

Вполне работает. Только grep принимает и выдает строчки => объектов вы не увидите на последнем конце. Ну так он и json так же может испортить. (Можно в принципе написать чуть сложнее, с использованием Where-Obkect — чтобы объекты доезжали до конца)

Единственный недостаток который я встречал, это если в ps1 включать обычный консольные команды, а потом весь вывод редиректить — тогда все падало (не уверен, что не исправили)
Ок, перейдем к главному. Apt-get install что?
только make && make install, только хардкор
ок, лёгким движением dh_make make install превращается в dpkg -i. Где оный make & make install под юниксы найти? (там ещё ./configure в комплекте, да?)
не специалист по юниксу, но там что, нет make? на макоси как и на линуксе есть, к примеру
make есть. Сырцов, которые бы правильно ./configure нет.
Если вам нужно из MSBuild сделать autotools-скрипты (я обычно пользуюсь xbuild и парой доп. команд в debian/rules для того чтобы скопипровать бинарники в нужные директории), можно воспользоваться monodevelop. Ещё есть пакет cli-common со скриптами для debhelper, прописывающий нужные зависимости и устанавливающий нужные сборки в GAC. Процесс сборки пакетов несколько отличается от стандартного для сишки, что не удивительно, с явой примерно так же.
Вот мы и пришли к главному — mono снизу. Гигантский, неподъёмный, который никто на сервер просто так не пустит (ради мелких cli-утилит).

Плюс полная несовместимость ни с кем, кроме себя (я ниже писал про разницу между «умный шелл» и «простые утилиты через pipe»).

Условно говоря, вывод curl'а «как есть с js'ом» в powershell не загонишь, и «похакать sed'ом посредине json'а» тоже непохакаешь.

Фреймворк слишком объёмный и претендующий на среду исполнения. А это означает, что все, кто не с этой средой — в пролёте.

То есть просто прямой анти-юникс.
Что именно вы имеете ввиду?
Если отсутствие packange managers, то есть 3rd party: chocolatey.org/
и на этапе CTP находится OneGet github.com/OneGet/oneget/wiki/cmdlets

Если то, что PoSh не работает под юниксом, то так сразу бы и сказали :)
Начните свой день в iPython с «import sh» (https://pypi.python.org/pypi/sh). Делает именно то, что вы хотите, только на питоне: «for a in ls('/'): [...]».
Спасибо, посмотрю. Возможно, очень близко к тому, что мне нужно в минимальном виде (хотя идея всё-таки большая — сделать инструмент, не зависящий от языка программирования).
Фантастика на другом этаже. Все юниксовые шеллы — это интерпретаторы языков программирования, от которых сильно зависит запустится ваш однострочник или нет, не говоря уже о корректной работе. Попробуйте сделать одно и то же в bash и csh. Или даже в близкородственных zsh и bash. Разница есть, и не всегда очевидная (как во втором случае). Выбор состоит в том, от какого языка вам выгоднее зависеть.
Погодите, погодите. У разных шеллов разный синтаксис своих команд. Но модель pipe'ов у всех одна и та же. Я хочу иметь набор инструментов, которые бы не были завязаны на конкретный язык. Большинство же советующих «сделать такой шелл» (или рассказывающих о том, какой крутой powershell) просто этого не чувствуют. Для них, если один шелл умеет, этого достаточно. А я хочу научить все шеллы этому. Все. От бизибоксового sh до fish'а.
Пайп — это такой же языковой примитив, как и for или if. То, что он конвенционно везде одинаково выглядит не гарантирует того, что он везде одинаковый и даже будет одинаково работать. Перенаправлять потоки ввода-вывода можно и без пайпов, используя файловые дескрипторы и «шевроны» (>).
Да. Но среди всех примитивов, pipe и fd — самые живучие и присутствующие во всех операционках с момента победы юникса. Даже в виндах pipe ведёт себя так же, как и в юниксе.

Какой значок будет использоваться в конкретном шелле не важно. Предложенная реализация будет работать с любыми значками перенаправления. Она зависит только от стыкования stdin одной программы в stdout другой.
Тогда вам нужно соблюдать три правила: получать данные через стандартный ввод, выдавать результат в стандартный вывод и сообщать об ошибках в стандартный вывод ошибок. С остальным разберутся за вас.
Ну да. К этому я хочу добавить утилиты, которые будут принимать и отдавать json.
Добавлю, что большинство проблема эргономики на Windows решаются использованием нестандартного терминала, ConEmu, например.
Мне кажется, или вы пытаетесь изобрести PowerShell?
Во-первых я про него в посте написал, а во-вторых, я пытаюсь его сделать удобным и не завязанным на конкретный язык/среду исполнения.
Я бы скорее сказал, это попытка прикрутить «объектность» к существующему юниксовому пайплайну, не трогая существующие наработки в нем (в отличие от PS, который замещает собой большую часть досовых команд).

И, кстати, более грамотная попытка, имхо. В PS мне активно не нравится то, что в пайпах там именно объекты — т.е. сущности с поведением. Имхо, это противоречит самой концепции «трубы», через которую льются данные, а поведение предоставляют программы с той и с другой стороны.
А почему объединение данных и поведения это плохо? Это позволяет выделять общие абстракции не меняя данных.

Пример:

в powershell объектах могут быть вычислимые свойства которые позволяют обрабатывать все объекты одинкаово:

ls | gm | ?{ $_.Name -match '^PS'}
Name MemberType Definition
— — —
PSChildName NoteProperty System.String PSChildName=@OpenWithToastLogo.png
PSDrive NoteProperty System.Management.Automation.PSDriveInfo PSDrive=C
PSIsContainer NoteProperty System.Boolean PSIsContainer=False
PSParentPath NoteProperty System.String PSParentPath=Microsoft.PowerShell.Core\FileSystem::C:\WINDOWS\system32
PSPath NoteProperty System.String PSPath=Microsoft.PowerShell.Core\FileSystem::C:\WINDOWS\system32\@OpenWithToastLogo.png
PSProvider NoteProperty System.Management.Automation.ProviderInfo PSProvider=Microsoft.PowerShell.Core\FileSystem

И почему объекты нарушают концепию пайпа а не расширяют ее?
В вашем примере, Name — это как раз данные. Поведение — это методы вроде CopyTo.

Объекты нарушают не столько саму концепцию пайпа, а концепцию шелла в целом. Поведение, обработка данных — это команды. Передача данных от команды к команде — это пайпы. Когда у вас объекты в пайпах начинают нести свое собственное поведение, вся система становится размытой, и непонятно, где именно искать нужное поведение. Например, в чем разница в PS между copy-item и CopyTo()? И почему вообще они существуют как две отдельные сущности с разным поведением?
CopyTo это специфичный для файлов способ копирования 1 файла унаследованный из .NET, Copy-Item это копирование общее для powershell причем оно может выполняться как групповая операция. Достаточно посмотреть на набор параметров, чтобы понять разницу.

Фактически это операции с разными сущностями — CopyTo копирует файл, Copy-Item копирует набор элементов. Просто может быть набор из одного элемента, и этот элемент — файл.
Ну вот и возникает вопрос — а почему, собственно, copy-item — это не метод на коллекции элементов, раз уж у нас есть методы? По какой логике разделять функционал на коммандлеты и методы, и где его искать в каждом конкретном случае?

(копирование в данном случае — это просто пример, аналогичный вопрос можно задать про любую операцию)
1. С точки зрения чистого разума, да в принципе можно было бы создать чистообъектный шелл чтобы любая команда была методом чего-то. Например сейчас copy частично дублирует функионал ls (выборка айтоемов по маске), но наверное, пошли на поводу у привычек. Объектно-логичнее было бы сделать вместо cp *.txt c:\x что-то типа (ls *.txt).cp c:\x или, если придумать какие-нибудь литералы для масок: *.txt | cp x

2. Собственно методы обычно не являются функционалом шелла и наследуются от дотнет. Фактически у нас есть мультипарадигмальность: используй команды, специально написанные для шелла, если их не хватает у тебя есть настощие объекты дотнет
Да, и при таком подходе и пайпы не нужны тоже (точнее, они становятся синтаксическим сахаром для передачи параметров, как |> в F#).

Но это уже совсем другая история, которая к традиционному юниксовому шеллу имеет мало отношения.
ну собственно пайп и есть синтаксических сахар для передачи парметров — просто этот параметр — имеет строго один тип — текстовая строка (куда надо рендерить внутриенние объекты, потом опять парсить, потом опять рендарить и т.д)
А, например, ScriptProperty это данные или поведение?

BaseName ScriptProperty System.Object BaseName {get=if ($this.Extension.Length -gt 0){$this.Name.Remove($this.Name.Length — $this.Extension.Length)}els…
VersionInfo ScriptProperty System.Object VersionInfo {get=[System.Diagnostics.FileVersionInfo]::GetVersionInfo($this.FullName);}
Если они являются чистой фунцкией от других свойств объекта — то данные (причем те же самые, просто другое их представление).
VersionInfo является чистой функцией от других свойств (ему надо слазит в файл и посмотреть на версию)
Если такие (вычисляемые по использованию) данные приемлемы, то как назвать совокупность этих вычислений и невычислемых данных? Я бы назвал объектом.
Здравствуйте! Отличная идея. Сам иногда встречаюсь с необходимостью сделать однострочник, но вот отсутствие фильтрации, ВНЕЗАПНАЯ необходимость экранирования в самый неподходящий момент и порой наблюдающиеся проблемы с тем же sed — немного так бесят. Если собираетесь что-то писать, я с Вами — пишу на Python и буду рад помочь =)
Кстати, ls2json не сможет нормально распарсить вывод ls. Почему — написано здесь. Поэтому — os.listdir(".") и что-то из похожего для дополнительной инфы =)
Значит, jls, который понимает все осмысленные для json-вывода ключи.
Я для себя решил проблему виндовой консоли через установку гита в режиме separate shell и GnuWin32.
Первое дает полноценный bash-интерпретатор с поддержкой базовых команд типа ls, второе — полный набор программ типа grep, curl, wget итд.

image
Ну, тут проблема не как «на винды приличный шелл прикрутить», а как «сделать объекты в обычном пайпе без привязки к фреймворку/среде/ОС»
Добавьте к этому комплекту ConEmu, не пожалеете.
Мне не нравится идея учить старого пса (sh) новым трюкам (объектам), гонять данные из безформатья в джейсон и обратно. Опять же базовые утилиты вроде «ls» изначально нездоровы в контексте обмена данными, как было замечено выше. По-мне так эту актуальную проблему способен решить красиво только собственный ОО-шелл, но тогда это уже будет аналог PowerShell'а, которого вы так избегаете. Впрочем, не отговариваю.
Стоп. Где тут виден sh? Нет никакого sh. Есть pipe. Который действует по простым принципам:

1. Прочитанное из одного stdout передаётся в другой stdin
2. Передача прекращается, если одна из сторон закрывает pipe.
3. Stderr идёт параллельно.

Сам sh ни сном ни духом про формат того, что передаёт.

ls относится к coreutils (tr/cut/sort/cat), а к ним у меня очень мало претензии и очень много любви. Судя по обсуждению выше, для ls и многих других coreutils, работающих с внешними данными, придётся сделать свои аналоги для крутой работы.

Делать это _внутри_шелла_ — это как раз виндузятниковая модель (которой многие линуксы начали тоже страдать). Если это делается _внутри_ шелла, то использовать его вне этого шелла невозможно или неудобно.

Если же оно делается автономно-независимо, с простейшими соглашениями по входу/выходу, то их можно будет использовать _и_ в понтовом oo-шелле, и busybox'е, имитирующем sh+coreutils, и ещё где-то, где его не ожидают.

Собственно, я этой идеей загорелся, когда осознал, как она легко ложится на старую модель (и ни в одном месте ей не противоречит), и как легко её развивать в удобном направлении.
Даю скромный диванный прогноз: не взлетит. Просто потому, что оно не нужно.

Шелл хорош тем, что он убийственно прост, отчего им очень удобно решать простые задачи.

Усложнять же его смысла нет никакого: для более сложных задач уже есть удобные инструменты. От Python до любого другого языка программирования.
Именно этого я боюсь и хочу избежать. Чтобы человеку надо было что-то много и круто учить. Я предполагаю, что json в общем и целом все знают на уровне «примерно понимать о чём это». А дальше порог вхождения простой:

jsplit file | jget [3] | xargs (дальше обычный шелл).

Или

jgrep foo *|jiterate -each echo file ${FILENAME} at line ${LINE} match ${MATCH}

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

Условно говоря, если для применения первых 10 полезных фич надо будет прочитать больше 10-15 строк, значит это плохой старт.
На днях пробегала тут шикарная штука (правда, больше для питонистов, но все же): Pyp (Python Power at the Prompt).

Вот замечательное видео как оно работает.

Ну и сразу наглядный пример:
\> ls | pyp "p[0] | pp.sort() | p + ' first letter, sorted!'" #gives sorted list of first letters of every line
Да это же настоящий perl -nle!
Спасибо, интересно. Хотя не совсем то.
А может, лучше так — json ls, json find...? ну и симлики вида jls. Как в бизибоксе. Тогда и расширять проще, и внутренние реализации можно сделать для оптимизации или тех случаев, когда вывод стандартных команд сложно однозначно распарсить.
Именно так. Но для простоты понимания в тексте полные имена приводятся.
Примеры работы с структурированными данными?
У меня была похожая, если не в точности такая же идея. Я постоянно работаю с JS и хотел применить похожие идиомы к обработке данных в пайпе (filter, map, проекции/выборки). Также на идею таких утилит меня натолкнул просмотр одной из презентаций Рича Хикки, где он много рассказывал языковые средства и их аналоги в среде командной строки.

Правда я не думал, что такие утилиты будут кому-то полезными, к тому же операции разбора/вывода JSON будут весьма дороги (а их потребуется делать часто).
Ещё я думал о том, как было бы клёво, еслиб все утилиты поддерживали опцию --json, которая любой их вывод приводила бы к некоторому JSON. Далее этот вывод поступает непосредственно на утилиты для работы с JSON.
Правильность подхода статье именно в том, что он позволяет делать это все постепенно. Т.е. сначала определяется некий стандартный протокол для структурированных данных в пайпах с подборкой утилит для удобной работы с ним, и адаптеры для существующих неструктурных форматов. Если это постепенно взлетит, то тогда уже можно будет ожидать и --json из коробки в обычных утилитах.
В FreeBSD в этом году есть такой GSoC проект — machine readable output для всех утилит в базе. Человек, работающий над ним, пока смотрит в сторону yajl, который умеет выводить json потоково, но я, наверное, добавлю подобное в своем libucl, и мы будем использовать для этой задачи именно libucl (а, следовательно, поддержку всех форматов, что понимает ucl).
До конца надеялся на исходники. Желаю удачи в реализации!
Исходников есть примерно 40 строк. Показывать стыдно. Программист из меня фиговый, всё время срезать углы хочу.
У меня в моем проекте планируется набор системных утилит с выводом в json, попутно могу и для вас накидать.
Только по времени быстро не обещаю, занят сейчас.
язык Haskell
Идея хорошая!

Но >ls -la | ls2json | json-filter
— это что-то не то, плохо сочетается с «hand-candy (мало печатать)». Получается что надо написать обычную команду, потом написать input — многословность получается. Взять и переделать базовые утилиты (чтобы они имели опцию вывода в json) наверное сложно, да и опция опять добавит многословность. Написать свои? Но тогда они будут некрасиво называться, типа jls, jps и т.п. Я подумал что хорошим решением будет некий набор оберток над стандартными утилитами, плюс набор алиасов (наверное все шеллы умеют алиасы).
alias ls=json-ls
При этом json-ls может как сам читать директории (т.е. написать свою реализацию), так и парсить вывод обычного ls'а.
Когда json-ls запускается, он проверяет что на том конце пайпа. Если там утилита, которая понимает json (для этого в каждой json-утилите есть список «братьев и сестер»), то json-ls выдает json, если там что-то другое, то json-ls запускает обычный ls и передает ему все параметры. Думаю что оверхед будет небольшой.
Требуется набор компилируемых утилит, верно я понимаю? Или решения в скриптовых средах катят? (perl, node, ruby, shell)?
Много лет назад, когда мы еще дружили с перлом, я делал нечто похожее (даже с поддержкой CSV, JSON и XML). Собственно «расширение шелла» выглядело как кучка перл-прог, к которым со временем родился общий модуль для парсинга параметров из arg-ов и конфиг-файлов, сериализации объектов с сохранением типов и методов и т.д. Соответственно если у меня закисал мозг на каком-то однострочнике, я шел и писал прогу на перле. Да, сочленять перл-проги между собой через трубы было немного неэффективно (типа чтобы передать объект надо его заенкодить с одной стороны и задекодить с другой + динамически подгрузить его методы из общего модуля). И таки да, это занимало лишние 30 минут. Но, со временем, из зоопарка прог знание начало сегрегироваться в разумный набор утилит.

Гонять хэши было довольно увлекательно, но потом из «личных нужд» это переросло в «очень перспективное решение», и пришлось выкинуть перлы и трубы, и взяться за java, ant (для кастомизации сценариев) и message bus. Увы.

PS, кстати, отличная штука. И, наверное, .NET это плюс, а не минус, ибо зная API можно с ним поговорить, нарисовать свой cmdlet, даже если прога в явном виде это не позволяет. Что сильно более опенсоурсно и прогрессивно чем концепция «кучки черных ящичков» в никсах. Майки в этом смысле подняли планку.
Я очень надеюсь, что поддержка PS на никсах это вопрос коммодитизации ОС и, следовательно, времени. Это было бы реально круто.
Даже если MS решит всерьёз занятся продвижением PS на юниксах, оно очевидно будет плестись в хвосте у виндов (а у меня на виндоус всё работает, ничего не знаю), интересы юникс-платформы будут явно второстепенны перед платформой виндоус. Наверное, для пользователей виндоус это ок, но с точки зрения человека, у которого единственная винда на виртуалке — для криворукого drac'а на делловых серверах, это очевидная проблема.

Если же посмотреть, во что превращается репозиторий ПО после установки mono, то становится страшно. Бесконечные перекомпиляции модулей при каждом апдейте превращают процесс apt-get update в подобие установки обновления .net' framework'а на винды — долго, безумно долго, отчаянно долго. И я не понимаю, почему надо добровольно в это нырять.

Так что, спасибо, не надо.
Признайтесь честно, overengineering — это кайф, а не зло, правда?

Системы класса PoSh имеют две существенные проблемы:
1) они считают окружающий их мир 'legacy' или 'внешними', 'untrusted' источниками данных, с которыми надо особо обращаться, и всячески от них уклоняться — всё должно быть сведено в уютный мир .net.
2) Кривая вхождения такова, что человек либо всегда является профаном-любителем, либо его квалификация такова, что «а что он забыл в должности сисадмина?». То есть попытка объяснить в простых словах «как это устроено» (про любой командлет) потребует обширного курса по .net'у, более того, употребление и знание .net даёт явный плюс использующему. С точки зрения MS всё отлично — сложные скрипты на PoSh начинают напоминать обычную проприентарную магию (нашёл и скопипастил, работает, ура), а процесс изучения намертво подсаживает человека на платформу. Вместе с п.1 это делает мирок замкнутым и уютным.

Я же хочу юникс-вей. Это когда каждая компонента очень проста по архитектуре, легко описуема и ни в один времени не вываливает на человека «дивный новый мир».
Overengineering это метод борьбы с рутиной. Я вот сейчас рисую генератор мокапов по XML спеке вместо того, чтобы рисовать CRUD формочки в Visio. Меня трудно понять. Но, при этом, когда у меня получается, я делаю «80 часов работы до обеда» ;-)

1) Posh-у вообще фиолетово кто на другом конце пайпа, лишь бы плевался объектами и вообще поддерживал метафору. Хотите — заверните вашу историческую действительность в cmdlet и радуйтесь.
2) Да, Posh прицелен на DevOps. Это старая музыка под новую драм-машину, «пишущие админы». Майки очень на них ставят и, кстати, не зря. Большинство SaaS держится именно на них. Фанаты переименовывающие музыку в шеле их мало интересуют.

Я как раз и написал комментарий про то, что мои попытки что-то похожее сделать привели к довольно сложным (на мой взгляд) костылям. Но тем плюрализм мнений и конкурренция идей и хороши — может у вас получится то, что не получилось у меня.
overengineering, это когда вы потом окружающим предлагаете выучить все прилагающиеся технологии и начать пользоваться. Вне зависимости от того, есть ли время/желание у этих людей изучить эти технологии.

Ещё хуже, когда вы перестаёте рисовать и просто начинаете сейлзам эти файлы присылать, мол, там всё просто.
UFO just landed and posted this here
Круто. Мы пока что мучаемся с питонами, я итератор, Way, No — с input'ами. Го выглядит соблазнительно с точки зрения нативного кода.

После прототипирования (пока не понятно как некоторые вещи делать) можно будет подумать о компилируемой реализации.
Only those users with full accounts are able to leave comments. Log in, please.