Использование руби программ в качестве фильтров для поиска
Предыстория
Не далее как прошлой осенью я писал о том, как изнутри процесса определить, запущен ли он, используя инструмент grep. В комментариях мне посоветовали использовать pidof, но мне не удалось заставить его работать для руби, т.к. поиск происходит по имени запускаемого файла, а в случае руби-скрипта это всегда ruby. Но мне существенно удалось сократить получение списка запущенных процессов с таким же именем. Вместо:
`ps ax | grep #{File.basename(__FILE__)} | grep -v grep`.split("\n").map{ |l| l.strip.split(/\s+/)[0].to_i }.reject{ |pid| pid == Process.pid }получилось
`pgrep -f #{File.basename(__FILE__)}`.chomp.split(/\s+/).reject{ |pid| pid.to_i == Process.pid }Довольно часто мне необходимо отфильтровать вывод или содержимое файла хитрее, чем просто поиск по регулярному выражению. Поскольку мне очень нравится руби, и, как неоднократно писалось в этом блоге, я пытаюсь использовать его везде, где можно, то почему бы снова так не поступить?

Командная строка руби
Руби имеет умеренное количество ключей командной строки. Кратко они описаны в выводе:
ruby --helpНас в большей степени интересуют ключи -n и -p, которые создают цикл вокруг чтения из пайпа. Ссылка на подробности в конце статьи.
Например, мы хотим посчитать, сколько всего виртуальной памяти занимают все процессы браузера гугл-хром. В качестве источника информации будем использовать вывод команды:
ps axo "%p %z %c"В которой собраны только необходимые данные (занимаемая виртуальная память и имя процесса без аргументов) и пид (ну а вдруг?). А теперь этот вывод отправим не грепу, а нашему родному руби:
ps axo "%p %z %c" | ruby -nae 'num ||= 0; num += $F[1].to_i if $F[2] =~ /chrome/; END{puts "total chrome virtual memory size #{num} Kbytes"}'Что это означает? Ключ n означает, что вокруг нашего скрипта есть цикл вида:
while gets(); ... endКлюч a означает, что вместо переменной $_, куда автоматически попадает результат gets, мы можем использовать $F, который есть суть $_.split. А END содержит блок, который выполняется после цикла.
Ту же магию можно использовать и внутри запускаемых руби-скриптов. Например, если мы хотим найти какое-то слово внутри файла, выделить его цветом и вывести строку с номером, где это слово нашлось, то наш скрипт будет выглядеть вот так (файл look_for):
#!/usr/bin/ruby -n
BEGIN {
unless ARGV.size == 2
puts "Usage: ./look_for <word> <path/to/file>"
exit
end
str = ARGV.shift
}
next unless $_ =~ /#{str}/
printf "%6s%s", $., $_.gsub($&, "\e[31m#{$&}\e[0m")Теперь, если сделать этот файл запускаемым и запустить его:
./look_for word /in/some/fileТо можно увидеть неземную красоту. Кстати, обратите внимание на shift. Без него программа не работает, т.к. gets, который тут за кадром правит бал, пытается воспринимать все аргументы как пути к файлам, из которых непременно нужно что-нибудь прочитать.
Прочие прекрасные применения параметров командной строки руби я предлагаю пытливому читателю подсмотреть в ссылках ниже или найти самостоятельно.
