LINUX.ORG.RU

Функция для запуска программ/открытия файлов/обработки иных событий.

 , , , ,


0

3

Вариант на bash: http://pastebin.com/sWx7C4XC

Вариант для включения в .zshrc (есть автодополнение): http://pastebin.com/n9zz7s9u

Частично сам, частично не сам, набросал вот такую вещь. Замысел таков: вместо многочисленных лаунчеров типа xfce4-appfinder, gmrun и прочее, мне кажется более удобным запускать эмулятор терминала с соответствующей геометрией, и там запускать команды. Для того, чтобы это было больше похоже на лаунчер, и служит эта функция/этот скрипт.

Суть его такова: проверяем аргумент на соответствие шаблону (строки 6-15), если подходит - выполняем то или иное действие для строки, из которой убран, собственно, идентификатор (для примера - гуглинг по g:запрос и открытие википедии по w:страница). Затем, если то, что ввёл пользователь - это исполняемый файл в $PATH, то выполнить его (способы поиска в $PATH для bash и zsh разные). Дальше - если то, что ввёл пользователь, не находится в $PATH, то проверить - есть такой файл? Если нет, то открыть строку через exo-open (так как там может быть протокол http://, ftp:// или ещё что-то, не являющееся файлом, но открываемое exo-open). Если же это - файл, то проверить его на то, исполняемый ли он. Если исполняемый - то выполнить, иначе - открыть через exo-open.

Если какое-либо из действий было успешно - то открепить запущенное от терминала и закрыть оболочку (если запускается, как скрипт, то сам терминал не закроется, а просто прекратится выполнение скрипта с отвязкой запущенного от терминала. В случае же запуска, как функции zsh, закроется сам zsh, таким образом, будет поведение, как у лаунчеров: набрал, enter, лаунчер закрылся, команда выполнилась).

Вместо exo-open можно использовать xdg-open, kde-open, gnome-open — по желанию. Результат будет примерно одинаковым.

Реализовано ещё не всё, что хотелось бы. Конкретно, мне хотелось бы добавить обработку опций: например, чтобы при -t команда выполнялась в терминале, но я не знаю, как сделать обработку опций так, чтобы это не конфликтовало с основным аргументом функции/скрипта. Буду рад подсказкам. Все желающие приглашаются к тестированию, допилу, указанию на костыли и ошибки и прочее.

Запускать так: если zsh, то всё со второй ссылки добавить в конец .zshrc, и вызывать по «xo строка». Чтобы работало автодополнение, надо его включить в zsh (autoload -Uz compinit, вроде)

Если запускать, как отдельный скрипт на bash - то всё с первой ссылки положить в файл, сделать ему chmod +x и запускать по ./файл строка.

Видео-демонстрация того, как я это использую: https://dropmefiles.com/PUv3I (.ogv файл)

★★

Конкретно, мне хотелось бы добавить обработку опций: например, чтобы при -t команда выполнялась в терминале, но я не знаю, как сделать обработку опций так, чтобы это не конфликтовало с основным аргументом функции/скрипта.

примерно так, например:

xo [-t] command [args]

f1u77y ★★★ ()

Ты типа понтуешься, или что? Что сказать-то хотел?

r3lgar ★★★★★ ()

Сделай интерактивную «консоль» на python с cmd.

alozovskoy ★★★★★ ()
Ответ на: комментарий от f1u77y

Не совсем понимаю, как решить такую проблему: допустим, опция эта всегда на первом месте. Тогда можно проверить её через $1. Но тогда, во-первых, надо будет как-то её откусить от $* (все аргументы), во-вторых, если понадобится ввести ещё пару опций, то не ясно как регулировать их порядок (и тоже откусывание от $*).

Valdor ★★ ()
Ответ на: комментарий от r3lgar

Буду рад подсказкам. Все желающие приглашаются к тестированию, допилу, указанию на костыли и ошибки и прочее.

Valdor ★★ ()
Ответ на: комментарий от alozovskoy

Автодополнение хрен прикрутишь хорошее. Да и зачем питон?

Valdor ★★ ()
`echo $* | sed 's/g\://'`

${*#*:} — удалит первое двоеточие и весь текст до него.

if [ `compgen -c | grep -x "$1"` ]

if compgen -c | grep -qx -- "$1"

И да, какой смысл это несёт?

shdown ()
$*

$* соединяет аргументы первым символом $IFS, а не заключенные в кавычки переменные баш разбивает по IFS. Т.е. yourscript xdg-open 'https://www.google.ru/search?q=один два' запустит xdg-open https://www.google.ru/search?q=один два. Чтобы нормально передать/запустить аргументы, нужно делать "$@".

if [[ "$(dirname $1)" = "." ]]

[[ "$(dirname -- "$1")" == . ]], но и это не всегда сработает — $(...) съедает переводы строки в конце.

И да, если тебе нужно проверить, является ли $1 абсолютным путём: [[ $1 == /* ]].

// ЛОР почему-то не даёт запостить всё одним сообщением.

shdown ()

Конкретно, мне хотелось бы добавить обработку опций: например, чтобы при -t команда выполнялась в терминале, но я не знаю, как сделать обработку опций так, чтобы это не конфликтовало с основным аргументом функции/скрипта

man getopts.

option_terminal=0
while getopts 't' option; do
    case "$option" in
        t) option_terminal=1 ;;
        *) echo >&2 "Wrong usage!"
           exit 2 ;;
    esac
done
shift "$(( OPTIND - 1 ))" # теперь можно обрабатывать $1, $2, ..., $*, $@

...

if (( option_terminal )); then
   ...
else
   ...
fi
shdown ()

если то, что ввёл пользователь - это исполняемый файл в $PATH, то выполнить его (способы поиска в $PATH для bash и zsh разные)

Ужас какой.

hash -- "$1" 2>/dev/null либо command -v -- "$@" >/dev/null 2>/dev/null.

shdown ()
Ответ на: комментарий от shdown

Спасибо!

${*#*:}

Будет работать именно над переменной $*? Если да, то где это зашифровано? В первой звёздочке?

if [ `compgen -c | grep -x «$1»` ]

Спасибо, заменил. Это - проверка на то, лежит ли файл в $PATH. Проверку на наличие файла ниже по тексту команда из $PATH не пройдёт, а так она выполнится (и будет иметь приоритет перед файлом, с тем же именем, если он есть в текущем каталоге).

$*

А не наоборот? http://i.imgur.com/7dmglJy.png Если я правильно понимаю, все аргументы будут рассматриваться, как одна целая строка. Но я проверил - ты прав. Везде надо $* на $@ заменить?

if [[ «$(dirname $1)» = "." ]]

Тут мне надо проверить, лежит ли файл в текущем каталоге. Как посоветуешь сделать? грепнуть вывод ls?

hash — «$1» 2>/dev/null либо command -v — «$@» >/dev/null 2>/dev/null.

Не совсем понял намёка.

Valdor ★★ ()
Последнее исправление: Valdor (всего исправлений: 1)
Ответ на: комментарий от Valdor

Будет работать именно над переменной $*? Если да, то где это зашифровано? В первой звёздочке?

Да. ${var#expr} — удалить у $var как можно меньшее по длине expr в начале; думаю, понятно, что означает *:.

Спасибо, заменил. Это - проверка на то, лежит ли файл в $PATH

if hash -- "$var" 2>/dev/null

либо

if command -v -- "$var" >/dev/null 2>/dev/null

Везде надо $* на $@ заменить?

Кроме подстановки в URL, там как раз это и нужно.

Тут мне надо проверить, лежит ли файл в текущем каталоге.

Не понял. По логике тебе нужно проверить, (не) является ли он абсолютным путём.

shdown ()
Ответ на: комментарий от shdown

Насчёт последнего - там фишка в том, что если файл лежит не в текущем каталоге, то он может быть запущен по набору путь_к_файлу, а если он в текущем - то сработает ./имя_файла.

Valdor ★★ ()

Как я и предсказывал, автодополнение к опциям тоже у кого-то спрашивать будешь? Ввиду легкости добавления, могут и послать.

salsa ()
Ответ на: комментарий от shdown

Мне всё ещё не всё ясно насчёт $* и $@.

1.)

exo-open "https://www.google.ru/search?q=${*#*:}"

Здесь используется $*, потому что все слова после g: - это единый текст запроса и делить его вообще не надо. Здесь что-нибудь принципиально изменится, если вместо $* будет идти $@? Вроде, внутри кавычек между ними разницы быть не должно. Кстати, что изменится, если вместо «$*» будет $* (без кавычек)?

2.)

«$@»

Тут, ожидается команда с аргументами. Разве они не должны идти единым набором ($*)?

3.)

exo-open «$@»

Тут более-менее ясно.

Кстати, если я сейчас пытаюсь сделать:

./script.sh "http://google.ru/search?q=раз два три"

с кавычками или без, то получаю ошибку

./script.sh: line 18: http://google.ru/search?q=раз два три: Нет такого файла или каталога

Строка 18! Почему? О_о

Valdor ★★ ()
Ответ на: комментарий от Valdor

Строка 18! Почему? О_о

hash срабатывает на строках со слешами, замени на if command -v -- "$1" 2>/dev/null >/dev/null.

shdown ()
Ответ на: комментарий от Valdor

Мне всё ещё не всё ясно насчёт $* и $@.

Допустим, наши аргументы — xdg-open http://google.ru/search?q=раз два три.

"$@" — аргументы так, как они есть, несколько строк:

xdg-open http://google.ru/search?q=раз два три.

"$*" — аргументы, соединённые в одну строку первым символом $IFS — обычно это пробел:

xdg-open http://google.ru/search?q=раз два три.

$* — аргументы, соединённые в одну строку первым символом $IFS, разбитые на несколько строк по $IFS:

xdg-open http://google.ru/search?q=раз два три.

$@ (без кавычек) и какие-то манипуляции с $@ как со строкой — бессмыслица, но можешь посмотреть, что будет.

$IFS — это (по умолчанию!) пробел, таб и перевод строки, в этой последовательности.

See? Баш — это просто.

shdown ()
Ответ на: комментарий от shdown

Всё, я осознал и воспринял. Большое тебе спасибо за помощь. Думаю, когда понадобится getopts, сам осилю.

P.S. Обязуюсь таки прочитать ABS.

Valdor ★★ ()
Последнее исправление: Valdor (всего исправлений: 1)
Ответ на: комментарий от Valdor

Word splitting and pathname expansion are not performed on the words between the [[ and ]]

shdown ()
Ответ на: комментарий от shdown

То есть, не нужны, но и не помешают везде в [[ ]]? (а, ну у меня [[]] только в одном месте).

Valdor ★★ ()
Последнее исправление: Valdor (всего исправлений: 1)
Ответ на: комментарий от Valdor

P.S. Обязуюсь таки прочитать ABS.

Если это "адвансед баш чего-то то там", то вместо него лучше возьми вот это: http://mywiki.wooledge.org/BashGuide. Очень толково объяснено, почему весь шелл это очень тонкая оболочка над exec(2) другими системными вызовами и почему в нём пробел является основным элементом синтаксиса и как в нём взялось столько капканов из-за этого. Только это читать надо до написания, а не после. А ABS и прочий мусор из топа выдачи гугла лучше читать, только сверяясь предварительно с рейтингом на http://wiki.bash-hackers.org/scripting/tutoriallist.

d_a ★★★★★ ()
Ответ на: комментарий от shdown

Появился небольшой вопрос. Я заметил, что вот с такой строкой:

exo-open "https://www.google.ru/search?q=${*#*:}" &

Если у меня браузер уже открыт ранее, то запрос открывается, как надо, в нём. Если же браузер закрыт (и открывается новое окно), то запрос «дробится», т.е. вместо одного запроса из трёх слов будет открыт поиск первого слова запроса в гугле, и две вкладки, в них - второе и третьи слова. Так и при exo-open и xdg-open. Если же я указываю iceweasel (firefox) как открывашку, то всё отлично в обоих случаях. Как думаешь, здесь можно что-нибудь сделать, или это 100% вина xdg-open, exo-open, и остаётся только указывать браузер напрямую?

Valdor ★★ ()
Последнее исправление: Valdor (всего исправлений: 1)
Ответ на: комментарий от Valdor

Нужно делать URL-encode параметров запроса; можно это делать на баше (https://github.com/shdown/gt/blob/master/gt_play#L88-L103, замени _ans=$result на printf '%s\n' "$result"), либо вызывать что-то вроде

urlencode() {
    python3 -c 'from urllib.parse import quote_plus; import sys; print(quote_plus(sys.argv[1]))' "$1"
}
И делай
exo-open "https://www.google.ru/search?q=$(urlencode "$*")" &
                                                   # ^  ^ кавычки здесь обязательны

shdown ()
Ответ на: комментарий от shdown

В Bash первый вариант работает хорошо, а в zsh почему-то в начале запроса появляется много вот-таких вещей

v-v-v-v-v-v-v-v-v-v-v-v-v

Не знаешь, почему?

Valdor ★★ ()

Я думал, что у тебя там баш. В zsh printf -v не работает. Вот для zsh:

urlencode() {
    local LC_ALL=C # Forces splitting strings by bytes, not by Unicode symbols
    local symbol result
    local -i i len=${#1}
    for (( i = 0; i < len; ++i )); do
        symbol=${1:$i:1}
        if [[ $symbol == [-_.~a-zA-Z0-9] ]]; then
            printf %c "$symbol"
        else
            printf %%%02X "'$symbol"
        fi
    done
    printf '\n'
}

P.S. Я там вернул отрезание g: от строки, правильно вернул?

Да.

shdown ()
Ответ на: комментарий от shdown

Отлично, работает. Спасибо. Я правильно понимаю, что этот код всё то, что не является буквой-цифрой-чем-то-ещё, заменяет на то, как это должно быть представлено в url (%20 для пробела, например)?

Кстати, второй вариант является универсальным для bash/zsh?

Valdor ★★ ()
Ответ на: комментарий от Valdor

Я правильно понимаю, что этот код всё то, что не является буквой-цифрой-чем-то-ещё, заменяет на то, как это должно быть представлено в url (%20 для пробела, например)?

Да, см. https://en.wikipedia.org/wiki/Percent-encoding#Types_of_URI_characters.

Кстати, второй вариант является универсальным для bash/zsh?

Да.

shdown ()
Ответ на: комментарий от shdown

Good, good. Я просто эту функцию держу у себя в специальном zshrc, в котором обитает и автодополнение для неё, и твоя подсказка насчёт добавления xo в начало строки. Есть сочетание клавиш, которое открывает маленькое окно терминала (по размерам - под лаунчер) и zsh там читает именно этот специальный конфиг. Спасибо.

Valdor ★★ ()
Ответ на: комментарий от shdown

Алсо, переменная result там больше не нужна.

-    local symbol result
+    local symbol

shdown ()
Ответ на: комментарий от shdown

А, ну да, раз в ней не хранится никакое значение - мавр может уходить

Valdor ★★ ()
Ответ на: комментарий от shdown

Ещё один, наверное, последний вопрос:

Я тут заметил, что некоторые .desktop-файлы у меня открываются через exo-open (и, как следствие, выполняются. Как и должно быть), а некоторые - пытаются исполниться (с нулевым результатом).

Разницу заметил в выхлопе command -v

> command -v /usr/share/applications/conkeror.desktop
> command -v .local/share/applications/Team\ Fortress\ 2.desktop 
.local/share/applications/Team Fortress 2.desktop
> ls -l /usr/share/applications/conkeror.desktop
-rw-r--r-- 1 root root 2742 окт 25  2014 /usr/share/applications/conkeror.desktop
> ls -l .local/share/applications/Team\ Fortress\ 2.desktop
-rwxr-xr-x 1 user user 171 авг 18 11:14 .local/share/applications/Team Fortress 2.desktop
Видимо, разница в том, что второй - исполняемый. Суть вопроса: это нормальное поведение для command -v? Решить проблему я и сам смогу - просто рядом с command -v и проверкой на исполняемость ниже по тексту добавлю проверку на то, что этот файл - не *.desktop

Кстати, если command -v возвращает true для любого исполняемого файла (так ведь?), то, наверное, ниже по тексту можно убрать случай «файл исполняемый к нему указан абсолютный путь», ведь этот случай будет и так обработан, ведь command -v вернёт true. Или я неправ?

Valdor ★★ ()
Последнее исправление: Valdor (всего исправлений: 2)
Ответ на: комментарий от Valdor

Кстати, если command -v возвращает true для любого исполняемого файла (так ведь?), то, наверное, ниже по тексту можно убрать случай «файл исполняемый к нему указан абсолютный путь», ведь этот случай будет и так обработан, ведь command -v вернёт true.

Да. Если тебе нужно проверять на «исполняемый, но не с указанным путём, а лежащий в $PATH», то

if [[ $1 != */* ]] && command -v -- "$1" >/dev/null 2>/dev/null

Т.е. дополнительно проверять на то, не содержит ли $1 где-нибудь «/».

А почему у тебя .desktop-файл — исполняемый?

shdown ()
Ответ на: комментарий от shdown

Да. Если тебе нужно проверять на «исполняемый, но не с указанным путём, а лежащий в $PATH», то

Мне кажется, что это не нужно. Или я не учитываю какой-то юзкейс?

Получается, что command -v обеспечит нужное поведение на случаи, если:

  • Аргумент - исполняемый файл, указанный по абсолютному пути
  • Аргумент - команда из $PATH
  • Аргумент - встроенная команда оболочки

Ниже по тексту рассмотрен вариант

  • Аргумент - исполняемый файл, указанный по относительному пути

Это - все случаи, когда файл надо исполнить, в остальных случаях - открыть.

А чёрт его знает. Я прочитал спецификацию .desktop - так быть не должно, но это - автоматически созданный стимом .desktop, и следует ожидать, что все остальные созданные им же будут такими же, проще просто добавить страховку на случай непонятного поведения проги.

Valdor ★★ ()
Последнее исправление: Valdor (всего исправлений: 2)
Ответ на: комментарий от Valdor

Да, ты прав. Алсо, можно вынести форк+disown+exit в отдельную функцию:

xo_spawn() {
    "$@" &
    disown
    exit
}

И писать

xo_spawn some-program
вместо
some-program &
xo_exit

shdown ()
Ответ на: комментарий от shdown

Интересную вещь заметил. Если я, допустим, через этот скрипт запускаю command -v (нахрен не надо, чисто чтобы проверить, умеет ли он работать с встроенными командами шелла), то если я запускаю через bash:

bash script.sh command -v true

то результат как должен быть, а если через zsh:

zsh script.sh command -v true

то xo_spawn:1: command not found: -v

Почему так?

P.S Разумеется, совершенно не критично, ибо для этого скрипта такая функциональность абсолютно не нужна.

Valdor ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.