UNIX (s)hell, pt4 · Neg blog

UNIX (s)hell, pt4

Функциональное программирование в zsh. Я здесь рассмотрю два способа, которыми можно обогатить возможности для написания скриптов, это xargs и zsh-functional, которые позволяют заменить циклы аналогами list-comprehersions, а также вводят новые синтаксические возможности, которые позволяет писать меньше букв в однострочнике.

xargs

xargs это довольно известная утилита, которая служит для формирования и проброса списка аргументов в другую команду. Её преимуществом над циклами является простота, краткость, а также возможность легко распараллелить выполнение. Может поочередно передавать элементы списка на выполнение команде, что может быть полезно в том случае, если команда не может принять больше одного аргумента некоторого типа.

Детальный обзор опций можно посмотреть, пожалуй, здесь: https://azarkevich.blogspot.ru/2010/01/xargs.html

Например допустим мы хотим обработать большой список аргументов, который может содержать пробелы и кавычки, это можно сделать вот так:

find -type f -name *.cpp -print0 |xargs -0 wc -l

Скопировать файлы из текущей директории в другое место с помощью xargs:

echo *|xargs -i cp ./{} $1

Это эквивалент

cp * $1

За исключением того что не нужно думать об экранировании пробельных символов и прочей ерунде. Здесь ключ -i нужен для того чтобы реализовать подстановку аргумента в нужное место с помощью {} по аналогии с find, parallel и некоторыми другими командами.

Ещё один сценарий это простая работа с разделителями:

echo '1-2-3-4' | xargs -d '-' -n 1

А вот и возможность параллельного выполнения – допустим у нас под рукой нет nmap, тогда обработка списка из ip может принять следующий вид:

seq 1 254|xargs -n 1 -i ping -c1 192.168.0.{}

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

Распараллелить эту операцию очень просто, с помощью опции -P, например так мы запустим эту команду в 10 потоков:

seq 1 254|xargs -n 1 -P 10 -i ping -c1 192.168.0.{}

Что очень значительно ускоряет процесс.

В общем думаю все поняли, что xargs штука очень полезная. К сожалению она не может делать проброс, например, во встроенные функции bash или zsh. Существует хак, который называется zargs, который пытается делать это, но к сожалению его удобство использования и надежность оставляют желать много лучшего. Bash вроде как поддерживает возможность экспорта функций через export -f function_name, но я не знаю насколько это хорошо работает. Проброс в alias тоже по-умолчанию тоже не работает, правда это небольшая беда, поскольку можно воспользоваться чем-то вроде echo $aliases[vmpd], где vmpd это нужный алиас.

zsh-functional

Существует ещё один способ как выполнять разные интересные штуки. Возможно что-то подобное есть и для bash. Называется это zsh-functional и предоставляет функции высших порядков, найти можно вот здесь: https://github.com/Tarrasch/zsh-functional

Пример использования помимо тех, которые есть на оффициальном гитхабе:

folda '$1+$2' $(find -type f -regextype posix-extended -regex '.*.(cpp|cc|h|hh|cs)' -exec wc -l {} \; | awk '{print $1}')

Подсчет количества строк в проекте, в данном случае unreal engine. По-моему выглядит просто и красиво.)

В отличие от xargs поддерживает функции и алиасы, например вот так можно запустить мой враппер для vim без v_standalone:

[~/.zsh] >> eachf v $(find -name *.zsh -print0|xargs -0)
comments powered by Disqus