ruby -e для упрощения работы в консоли

в 0:15, , рубрики: ruby, консоль, однострочники, эффективность работы

Как, думаю, многим известно, Ruby создавался под влиянием Perl,
поэтому нет ничего удивительного в том, что Ruby может подменить Perl
в его нише "практического извлечения данных и составления отчетов". В
данном небольшом посте речь пойдет об использовании ruby для мелкой
обработки текста в консоли.

TL;DR

Запоминаем две конструкции:

  1. ... | ruby -lne <CODE>
  2. ruby -lne <CODE> file1, file2, ...

В первом случае входными данными будет вывод предыдущей команды, а во
второй — конкатенация содержимого файлов.

CODE будет выполняться для каждой строки входных данных, которая будет
записываться в переменную $_. Важно: строки будут без завершающего
n (за это отвечает флаг -l).

Примеры

Отраженный cat:

ruby -lne 'puts $_.reverse' file-to-show.txt

Вывести только первые 10 символов имени файлов в текущей директории:

ls | ruby -lne 'puts $_[0..9]'

Немного подробностей

Предопределенные переменные

В Ruby есть множество предопределенных переменных, о существовании
многих из которых мы с вами можем даже не знать. Среди них есть и
перекочевавшие из Perl, например, $_ и $< (на самом деле, в Perl
нет такой переменной, но есть конструкция оператора ввода <>,
читающая из файлов/stdin и устанавливающая $_).

С их списком можно ознакомиться
здесь.

В рамках темы поста советую обратить внимание на вышеупомянутые $_ и
$<, а помимо них на: $~, $1, $stdin, ARGV, $stdout, STDIN и
STDOUT.

Страшный секрет gets

Возможно, многие использовали gets для того, чтобы запросить ввод с
клавиатуры. Однако далеко не все знают, что он проверяет содержимое
ARGV — аргументов командой строки.

Когда ARGV непустой, наш gets считает, что там указан список
файлов, берет первый из них и пытается прочитать строку
оттуда.

Возьмем скрипт:

# myscript.rb
puts gets

И запустим его с помощью ruby myscript.rb. Как и ожидалось,
программа ждет нашего ввода.
А теперь запустим его вот так:

ruby myscript.rb no-such-file

Произойдет ошибка: файла "no-such-file" не существует. А теперь
изменим скрипт:

# myscript.rb
ARGV.pop
puts gets

Теперь интерпретатор опять ожидает нашего ввода, т.к. с помощью pop мы
выкинули наш "no-such-file".

Опции интерпретатора

Вот так выглядит мой шаблон однострочника:

ruby -lne <CODE> [file1, file2, ...]

(зачастую без -l)

Описание используемых и некоторых потенциально полезных опций:

  • -e <CODE> — вынуждает интерпретатор не пытаться искать скрипт
    среди аргументов и выполнить CODE.
  • -n — оборачивает скрипт (или код, переданный с помощью -e) в
    цикл while gets. Метод gets неявно устанавливает возвращаемое
    значение переменной $_ (привет, Perl!), которую мы и должны
    использовать. Важно: строка будет заканчиваться n.
  • -l — для простоты можно считать, что она просто удаляет символ
    новой строки n из $_.
  • -p — работает точно так же, как и -n, но после каждой итерации
    выводит содержимое $_. Т.е. подразумевается, что вы будете его
    менять. Например: ls | ruby -pe '$_.upcase!'
  • -C <DIR> — меняет рабочую директорию.
  • -a(от auto-split) — используется совместно с -n или -p и
    устанавливает переменную $F, равной $_.split.
  • -F — устанавливает стандартный разделитель для String#split
    ($;). Теоретически, может быть полезно совместно с -a. Например,
    так можно обрабатывать простенькие .csv

Заключение

Впервые использовать ruby -e меня натолкнула команда cut. Мне ее
приходилось пару раз использовать, и каждый раз мне нужно было
открывать мануал, который моя тугая голова не хотела быстро понимать.

В конечном итоге я подумал: "Да, я не умею пользоваться
cut/awk/sed. Но зато я неплохо знаю Ruby, почему я не могу для
всяких мелочей использовать его?".

Собственно, в конечном итоге вместо запоминания множества команд мне
достачно было запомнить только конструкцию, полученную опытным путем:

ruby -lne CODE

И все. Все мои проблемы с построчной обработкой текста решены.

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

P.S. Напоследок вот пример использования:

Скачал сезон сериала, а там имена файлов некрасивые, вроде "s01e01 — super
release by super-mega-macho.mkv", хочу их переименовать, чтобы в
медиатеке все было красиво. Пожалуйста:

ls | ruby -lne 'File.rename($_, "#{$_[0..5]}.mkv")'

Автор: Дмитрий Нон

Источник

Поделиться

* - обязательные к заполнению поля