выполнение команды в zsh в зависимости от синтаксиса введённой строки


ia аватар

ia - Posted on 14 Декабрь 2008

Бывает так, что надоедает дописывать к началу скопированной в терминал, к примеру, из браузера, ссылки, саму команду, которая должна эту ссылку обработать. Например, вот так (где | - текущее положение курсора):

Если Вам это знакомо, то Вы понимаете, о чём я. Причём речь не обязательно о git:// для git clone; это может быть lp: или bzr:// для bzr branch, http:// - для wget или aria2c, file:/// - для cd ну и т.д. и т.п. - вариантов множество и примеры использования могут зависеть от того, с какими видами пар ссылка/действие приходится работать. Конечно, можно настроить короткие алиасы для команд, но можно и пойти чуть дальше - можно настроить, что же должен выполнить zsh в зависимости от синтаксиса введённой строки. Для этого нужно отредактировать .zshrc файл, добавив туда функцию precmd (чуть подробнее про precmd можно прочитать в комментариях к коду в этом совете - http://linsovet.com/content/настройка-приглашений-zsh) примерно следующего содержания:

...
function precmd
{
    cmd=`cat $HISTFILE | tail -1`; #определяем текущую введённую команду
    if [ "`echo $cmd | grep -e "^git://" -e "^lp:" -e "^bzr://" -e "^bzr+ssh://" -e "^http://" -e "^file:///"`" != "$NULL" ]; then
        #если команда начинается с нужного нам текста, то
        #записываем в переменную type_path тип ссылки
        type_path=`echo $cmd | cut -d ":" -f -1`;
        case "$type_path" in
            #в зависимости от типа ссылки, делаем соостветствующее действие
            #в конце каждого действия echo "" >> $HISTFILE нужно для того,
            #чтобы при закрытии терминала и открытии его в следующий раз команда не выполнилась повторно
            git ) git clone $cmd; echo "" >> $HISTFILE ;;
            bzr | bzr+ssh | lp ) bzr branch $cmd; echo "" >> $HISTFILE ;;
            http ) aria2c $cmd; echo "" >> $HISTFILE ;;
            file ) cd "`echo "$cmd" | sed 's/\%20/\ /' | cut -d "/" -f 3-`"; echo "" >> $HISTFILE ;;
            * ) ;;
        esac;
    else
        type_path="";
    fi
 
    # ...	
 
	return 0;
}
...

Теперь можем проверить, как это работает:

> <c-v>
> git://github.com/pieter/git-bzr.git|<enter>
zsh: no such file or directory: git://github.com/pieter/git-bzr.git
Initialized empty Git repository in /home/ia/Templates/git-bzr/.git/
remote: Counting objects: 19, done.
remote: Compressing objects: 100% (12/12), done.
remote: Total 19 (delta 6), reused 19 (delta 6)
Receiving objects: 100% (19/19), 11.47 KiB, done.
Resolving deltas: 100% (6/6), done.
>

Думаю, суть ясна, и доработать выполнение собственных команд-ссылок для собственных нужд при базовых знаниях shell-комманд труда не составит.
Happy zsh'ing :-)

0
Ваша оценка: Ничего

Поправочка.
Оказывается, fc -- это тоже POSIX sh.

Сначала о хорошем. Замечательная идея, правда!

Довольно странный метод вычисления последней команды -- поиском по HISTFILE. Не ровён час два человека одновременно работают -- вот смеху-то будет.

В zsh есть штатное средство работы с историей команд: fc . То, что вам нужно, делается с помощью `fc -ln -1` .

Для определения того, является ли команда первой в свежеоткрытом терминале не нужно ломать $HISTFILE (а если там timestamp-ы?), достаточно проверить $LINENO.

Выделение type_path также выглядит непрямовато. Зачем выкрутасы с grep-ом, а затем -- с cut-ом, когда со времён POSIX sh есть выделяющая подстановка вида "${cmd%%://*}"? То же самое касается обработки file:///.

Ещё про file:///. Замена "%20" на пробел -- далеко не самый надёжный способ urldecode. Другое дело, что правильный инструмент для этого найти непросто. Я пользуюсь http://www.billposer.org/Software/uni2ascii.html .

Мелкий недочёт: aria2c $cmd и т. п. А если в cmd будут вопросительные знаки?

Отдельно расстроило использование нигде не определённой переменной "NULL" (export NULL="тыква" немножко меняют стиль работы этой precmd() ).

Итого:

precmd ()
{
    local cmd type_path
    cmd=`fc -ln -1`;			# Определяем текущую введённую команду
    type_path="${cmd%%://*}"		# Обработка URL://
    test "$LINENO" -le 1 || case "$type_path" in
        git) git clone "$cmd";;
	bzr|bzr+ssh|lp) bzr branch "$cmd";;
	http) aria2c "$cmd";;
	file) cd "$(echo "${cmd#file://}" | ascii2uni -qa J)";;
	*) ;;
    esac
    # Теперь можно обрабатывать cmd ещё как-нибудь :)
    return 0;
}

Happy zsh'ing. Кстати, от zsh осталось только сама precmd и fc :-)

It's actually a great and useful piece of info. I am satisfied that
you simply shared this helpful info with us. Please keep
us informed like this. Thanks for sharing.

В принципе работает, но есть парочка недачетов:
1) если по завершению действия не водить каких либо команд а нажать Enter, то начнется повторная загрузка предыдущей команды
2) если резко прервать команду закрытием терминала, по последующее его открыти автоматическа запускает прерванную команду на повтор.

отличные улучшения Ж:-)
1. а нельзя это в preexec загнать, тогда команда будет уже в $*
2. зачем test "LINENO"? я так понимавю все равно в *) вывалится?

Отправить комментарий

Google Friend Connect (leave a quick comment)
loading...
Содержание этого поля является приватным и не предназначено к показу.