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

Как, думаю, многим известно, Ruby создавался под влиянием Perl, поэтому нет ничего удивительного в том, что Ruby может подменить Perl в его нише «практического извлечения данных и составления отчетов». В данном небольшом посте речь пойдет об использовании ruby для мелкой обработки текста в консоли.
TL; DR
Запоминаем две конструкции:
... | ruby -lneruby -lnefile1, 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 [file1, file2, ...]
(зачастую без -l)
Описание используемых и некоторых потенциально полезных опций:
-e— вынуждает интерпретатор не пытаться искать скрипт среди аргументов и выполнитьCODE.-n— оборачивает скрипт (или код, переданный с помощью-e) в циклwhile gets. Методgetsнеявно устанавливает возвращаемое значение переменной$_(привет, Perl!), которую мы и должны использовать. Важно: строка будет заканчиваться\n.-l— для простоты можно считать, что она просто удаляет символ новой строки\nиз$_.-p— работает точно так же, как и-n, но после каждой итерации выводит содержимое$_. Т.е. подразумевается, что вы будете его менять. Например:ls | ruby -pe '$_.upcase!'-C— меняет рабочую директорию.-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")'
