Небольшой сценарий bash для быстрого редактирования сценариев в $ PATH

Оставаясь верным мантре: «Когда вы что-то делаете в третий раз, вы автоматизируете», Я собрал приличную коллекцию сценариев оболочки, которые живут в ~/bin. Некоторые из этих скриптов содержат полезный шаблонный код или просто вещи, которые я не могу заставить себя запомнить (например, цветовой вывод). Другие сценарии, которые я время от времени дорабатываю. Хотя это и не очень больно, я очень ленив. Вместо того, чтобы печатать vim ~/bin/some_script, Я написал еще один сценарий, расширяющий some_script на полный путь (используя which) и открывает его в vim. Я полностью доволен тем, как работает скрипт, и добавил несколько основных удобств, таких как проверка наличия каких-либо (действительных) аргументов и так далее. По правде говоря, я не так много писал на bash в последние годы, и некоторые выражения / приемы, которые я использовал, кажутся неуклюжими. Я знаю, что раньше у меня было что-то подобное в моем .profile, но это конкретное воплощение скрипта / функции так и не попало в мой репозиторий github misc.

Короче говоря, я хотел бы знать, есть ли что-то, что я мог бы улучшить. Сначала код, затем некоторые конкретные вещи, которые мне просто не подходят.

Usage() {
    cat <<-__EOF_
${0##*/} finds executables in PATH and opens them in vim - useful to quickly edit your scripts
    -o         : opens all scripts using o flag (equivalent to vim -o <paths>)
    -O         : similar to -o, but uses -O flag (so vim -O <paths>)
    -h         : Display help message

__EOF_
    exit "${1:-0}"
}

flags=""
paths=""

while getopts :oOh f; do
    case $f in
        o)
            flags="-o"
            ;;
        O)
            flags="-O"
            ;;
        h)
            Usage
            ;;
        *)
            echo "Unknown flag ${f}${OPTARG}"
            Usage 1
            ;;
    esac
    shift
done

[ $# -lt 1 ] && echo "No arguments given" && Usage 2

for b in "$@"; do
    p=$(which "${b}") && paths="${paths} ${p}"
done
[ ${#paths} -gt 0 ] || :(){ echo "No valid executables found in path" && exit 3; };:

# We want globbing and word splitting here
# shellcheck disable=SC2086
vim $flags $paths

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

  • [ $# -lt 1 ] && echo "No arguments given" && Usage 2 Я делаю это все время, и он отлично работает, но объединяю 3 команды в цепочку && это выглядит некрасиво. Если есть более чистый и лаконичный способ сделать то же самое, я весь в ушах.
  • p=$(which "${b}") && paths="${paths} ${p}". Я не сторонник использования подоболочки здесь. я использую #!/usr/bin/env bash для моего хэшбэга я не уверен, что мне нужна подоболочка. Если нет, то какой была бы альтернатива? Какие плюсы и минусы?
  • [ ${#paths} -gt 0 ] || :(){ echo "No valid executables found in path" && exit 3; };: то же самое, что и цепочка вещей, только на этот раз, потому что я использую ||, затем &&, Я просто оборачиваю последние 2 выражения в функцию и вызываю ее. Это запах ИМО. Я мог бы изменить это на [ ${#paths} -le 0 ] && ..., но тогда это просто еще одна цепочка. Лично я предпочитаю -gt над -le или же -eq в этом случае. Я также предпочитаю иметь конечную команду (vim), чтобы быть последним, так что код выхода vim передается обратно в случае успеха (без необходимости явного выхода, например [ ${#paths} -gt 0 ] && vim $flags $paths && exit или же exit $? если хотите быть супер-явным)

Могут быть и другие вещи, которые я могу улучшить, поэтому не стесняйтесь указывать на них.

1 ответ
1

Используйте shebang

#!/usr/bin/env bash

Я вижу, ты уже это делаешь.

В bash предпочитайте [[...]] над [...]. Двойная скобка условная команда
дает вам больше возможностей (включая сопоставление регулярных выражений) и меньше сюрпризов (особенно в отношении переменных без кавычек).

С getopts петля, я предпочитаю shift в конце:

while getopts ...; do
    case $opt in
        ...
    esac
done
shift $((OPTIND - 1))

Разрешите функции использования получать сообщение об ошибке:

Usage() {
    [[ -n $2 ]] && echo "$2" >&2
    # ... rest is the same
}

Это упрощает некоторые утверждения

(( $# > 0 )) || Usage 2 "No arguments given"

Использовать command -v вместо which

Используйте массив для хранения путей. Нет другого хорошего способа сохранить список вещей, в которых любой из них может содержать пробелы.

paths=()
for b in "$@"; do
    p=$( command -v "$b" ) && paths+=("$p")
done

Вам нужно выполнить подстановку команд (также известную как подоболочка), чтобы вы могли записать вывод.

Функция «толстой кишки» заставляет меня съеживаться. Для ясности используйте if вместо длинных логических цепочек

if (( ${#paths[@]} == 0 )); then
    echo "No valid executables found in PATH" >&2
    exit 3
fi

И предпочитаю цитирование, а не разбиение слов:

vim $flags "${paths[@]}"

Да, сценарий завершится со статусом выхода vim. Если вы хотите быть очень аккуратным, вы можете заменять процесс сценария с vim:

exec vim $flags "${paths[@]}"

  • Спасибо за вклад. Функция двоеточия действительно казалась грязной при записи. Просто из любопытства: какая-то конкретная причина использовать (()) для числовых сравнений по [ -eq ] & co? Я понимаю, почему предпочтительнее использовать > из -gt, но, как ни странно, я обнаруживаю, что делаю меньше глупых ошибок, используя последнее (я, вероятно, испортил < против > хотя бы раз в неделю — стыдно, я знаю)

    — Элиас Ван Отегем

  • Просто личное предпочтение. ((...)) позволяют вам назначать переменные внутри него, а также ссылаться на переменные без $ для создания читаемых C-подобных выражений — ((sum += hours * hourly_rate))

    — Гленн Джекман

  • ((...)) не очень хорошо сочетается с set -e хотя: если арифметическое выражение равно нулю, статус возврата равен 1 — это хорошо для условий, но может сбивать с толку источник ошибок.

    — Гленн Джекман

  • ваше здоровье. В этом случае я буду использовать квадратные скобки для сценариев bash. Реализованы практически все остальные ваши предложения.

    — Элиас Ван Отегем

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *