Сценарий оболочки Linux: запускать программу, только если она существует, игнорировать ее, если она не существует

Может быть что-то вроде этого:

find YOUR_DIR -maxdepth 1 -type d -exec echo -n "{}  " \; -exec git --git-dir={}/.git symbolic-ref -q --short HEAD \;

Пример вывода:

.  fatal: Not a git repository: './.git'
./zabbix2  master
./dnsmasq  fatal: Not a git repository: './dnsmasq/.git'
./puppet-network  master
./resolv_conf  fatal: Not a git repository: './resolv_conf/.git'
./old  fatal: Not a git repository: './old/.git'
./php_ini  fatal: Not a git repository: './php_ini/.git'
./stdlib  fatal: Not a git repository: './stdlib/.git'
./mcollective  master
./netlogon  master
./debian  master
./apt  fatal: Not a git repository: './apt/.git'

Вы можете поиграть с первой командой 'exec', чтобы изменить необходимый формат вывода папки.

15
30.01.2019, 11:30
8 ответов

В моей интерпретации использовалась бы функция-оболочка с тем же именем, что и инструмент; в этой функции выполнить настоящий инструмент, если он существует:

figlet() {
  command -v figlet >/dev/null && command figlet "$@"
}

Тогда вы можете оставить figlet arg1 arg2...без изменений в своем скрипте.

@Olorin придумал более простой метод :определить функцию-оболочку, только если нам нужно (если инструмент не существует):

if ! command -v figlet > /dev/null; then figlet() { :; }; fi

Если вы хотите, чтобы аргументы figletпечатались, даже если figlet не установлен, измените предложение Олорина следующим образом:

if ! command -v figlet > /dev/null; then figlet() { printf '%s\n' "$*"; }; fi
35
27.01.2020, 19:49

Вы можете проверить, существует ли figlet

if type figlet >/dev/null 2>&1
then
    echo Figlet is installed
fi
14
27.01.2020, 19:49

Обычный способ сделать это с помощью test -xaka [ -x. Вот пример, взятый из /etc/init.d/ntpв системе Linux:

if [ -x /usr/bin/lockfile-create ]; then
    lockfile-create $LOCKFILE
    lockfile-touch $LOCKFILE &
    LOCKTOUCHPID="$!"
fi

Этот вариант основан на знании полного пути к исполняемому файлу. В /bin/lesspipeя нашел пример, который работает, комбинируя -xи команду which:

if [ -x "`which bunzip`" ]; then bunzip -c "$1"
else echo "No bunzip available"; fi ;;

Таким образом, это будет работать, не зная заранее, где в PATHнаходится исполняемый файл bunzip.

6
27.01.2020, 19:49

Другая альтернатива --шаблону, который я видел в сценариях автоматической настройки проекта:

if [ -x /usr/bin/figlet ]
then
    FIGLET=/usr/bin/figlet
else
    FIGLET=:
fi

$FIGLET "Hello, world!"

В вашем конкретном случае вы могли бы даже сделать,

if [ -x /usr/bin/figlet ]
then
   SAY=/usr/bin/figlet
elif [ -x /usr/local/bin/figlet ]
then
   SAY=/usr/local/bin/figlet
elif [ -x /usr/bin/banner ]
then
   SAY=/usr/bin/banner
else
   SAY=/usr/bin/echo
fi

$SAY "Hello, world!"

Если вы не знаете конкретный путь, вы можете попробовать несколькоelif(см. выше ), чтобы попробовать известные местоположения, или просто использовать PATH, чтобы всегда разрешать команду:

if command -v figlet >/dev/null
then
    SAY=figlet
elif command -v banner >/dev/null
then
    SAY=banner
else
    SAY=echo
fi

В общем, при написании скриптов я предпочитаю вызывать команды только в определенных местах, указанных мной. Мне не нравится неопределенность/риск того, что конечный пользователь мог вложить в свои PATH, возможно, в свои собственные ~/bin.

Если бы, например, я писал сложный сценарий для других, который мог бы удалять файлы на основе вывода определенной команды, которую я вызываю, я бы не хотел случайно подобрать в их ~/binчто-то, что могло бы или может быть не той командой, которую я ожидал.

5
27.01.2020, 19:49
type -p figlet > /dev/null && figlet "foo"

Команда bash typeнаходит команду, функцию, псевдоним, ключевое слово или встроенную функцию (, см.help type)и распечатывает местоположение или определение. Он также возвращает код возврата, представляющий результат поиска; true (0 ), если найдено. То, что мы здесь делаем, это попытка найти figletв пути (-p, что означает поиск только файлов, а не встроенных -модулей или функций, а также подавление сообщений об ошибках ), отбрасывание вывода (, который что > /dev/nullделает ), и если он возвращает true (&&), он выполнит figlet.

Это проще, если figletнаходится в фиксированном месте.:

[ -x /usr/bin/figlet ] && /usr/bin/figlet "foo"

Здесь мы используем команду test(, также известную как [), чтобы узнать, является ли /usr/bin/figletисполняемым (-x), и если да, то(&&)выполнить его. Я думаю, что это решение более переносимо, чем использование type, которое, как я считаю, является башизмом.

Вы можете сделать функцию, которая сделает это за вас:

function x() {
    if type -p "$1" >/dev/null; then
        cmd="$1"
        shift
        "$cmd" "$@"
    fi
}

(Кавычки необходимы из-за потенциальных пробелов)

Тогда бы ты просто сделал:

x figlet "foo"
3
27.01.2020, 19:49

о/, Я бы сказал что-то вроде

#!/usr/bin/env bash
# if figlet is installed :
if [ "$(which figlet 2>/dev/null)" ]; then
       # do what you wanted to do
       echo "foo"
       figlet "Starting"
       echo "moo"
       figlet "Working"
       echo "foo moo"
       figlet "Finished"
# if not
else
       # exit program with an error
       echo "please install figlet"
       exit 1
fi
0
27.01.2020, 19:49

В начале скрипта проверьте, существует ли figlet, и если нет, определите функцию оболочки, которая ничего не делает:

type figlet >/dev/null 2>&1 || figlet() { :; }

typeпроверяет, существует ли figletвстроенная оболочка -, функция, псевдоним или ключевое слово, >/dev/null 2>&1отбрасывает стандартный ввод и стандартный вывод, чтобы вы не получали никакого вывода, а если он не существует, figlet() { :; }] определяет figletкак функцию, которая ничего не делает.

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

При желании вы можете добавить диагностическое сообщение:

type figlet >/dev/null 2>&1 || { echo 'figlet not installed.' ; figlet() { :; } ; }

В качестве бонуса, поскольку вы не упомянули, какую оболочку вы используете, я полагаю, что она совместима с POSIX, поэтому она должна работать практически на любой оболочке.

5
27.01.2020, 19:49

Вы можете выполнить тестовое выполнение, подавляя любые выходные данные, и проверить код успеха/неудачи. Подберите аргументы к фиглету, чтобы сделать этот тест недорогим. -? или помощь --или версия --очевидны.

if figlet --help >/dev/null 2>&1 ; then
    # figlet is available
    echo "foo"
    figlet "starting"
    #etc
else
    rc=$?
    echo "figlet is not installed or not working correctly (return code ${rc})"
fi

Добавлено в ответ на комментарий ниже :, если вы действительно хотите проверить, что figlet существует, а не то, что его можно использовать, то вы должны сделать

figlet --help >/dev/null 2>&1 
rc=$?
if [ $rc -eq 127 ] ; then # 127 is "command not found" on linux bash 4.4.23(1)
    echo "command figlet not found"
else
    figlet "whatever" # use figlet
fi
0
27.01.2020, 19:49

Теги

Похожие вопросы