Почему мой скрипт Bash не распознает псевдонимы?

216

В моем ~/.bashrcфайле находятся два определения:

  1. commandA, который является псевдонимом для более длинного пути
  2. commandB, который является псевдонимом Bash-скрипта

Я хочу обработать один и тот же файл этими двумя командами, поэтому я написал следующий скрипт Bash:


#!/bin/bash

for file in "$@"
    do
    commandA $file
    commandB $file
done

Даже после выхода из моего сеанса и повторного входа в систему Bash выдает сообщение об command not foundошибке обеих команд при запуске этого сценария.

Что я делаю неправильно?

Зайд
источник
10
Кстати, нет необходимости входить и выходить, чтобы распознать псевдоним. Тебе нужно просто сделать source ~/.bashrc.
Чепанг
В моем случае я был подключен агентом SSH удаленно, после добавления псевдонима, когда я закрыл агент SSH и снова подключился, он начал работать.
Дав
Псевдоним - это способ сокращения команды. (Они используются только в интерактивных оболочках, а не в сценариях - это одно из очень немногих различий между сценарием и интерактивной оболочкой.)
Крис Руф

Ответы:

117

Прежде всего, как сказал ddeimeke, псевдонимы по умолчанию не раскрываются в неинтерактивных оболочках.

Во-вторых, .bashrcне читается неинтерактивными оболочками, если не установлена BASH_ENVпеременная среды.

Но самое главное: не делай этого! Пожалуйста? Однажды вы переместите этот сценарий куда-нибудь, где не установлены необходимые псевдонимы, и он снова сломается.

Вместо этого установите и используйте переменные среды как ярлыки в вашем скрипте:

#!/bin/bash

CMDA=/path/to/gizmo
CMDB=/path/to/huzzah.sh

for file in "$@"
do
    $CMDA "$file"
    $CMDB "$file"
done

источник
5
Это решение не работает для обычных aliasслучаев использования. Например alias mv="mv -v --backup=numbered".
Evi1M4chine
@ Evi1M4chine: Да, это так. По крайней мере, после того, как я отменил ненужное редактирование Жиля. Но в любом случае может быть лучше использовать другую переменную для параметров.
1
Ах, обратите внимание на отсутствие кавычек вокруг $CMDA/ $CMDB… Помимо переменных в верхнем регистре, которые зарезервированы для самого bash в bash, и это действительно работает, отсутствие кавычек делает меня действительно непростым… В любом случае, спасибо.
Evi1M4chine
@ Evi1M4chine: Ну что? 1. Я удалил цитаты сам в самом последнем редактировании. 2. откуда вы берете «зарезервировано для самого bash»? это будет первое, что я услышу об этом. 3. Если что заставляет вас неловко, как вы себя чувствуете об использовании Баша в первую очередь? Во всяком случае, используйте отдельную переменную для параметров, как я уже говорил.
1
@alvas: предполагается, что gizmoнет в пути или есть команда с тем же именем, но с более высоким приоритетом. иначе вы могли бы просто установить CMDAравнину gizmoв первую очередь.
161

Если вы заглянете на страницу руководства bash, то найдете:

Псевдонимы не раскрываются, когда оболочка не является интерактивной, если только параметр оболочки expand_aliases не установлен с помощью shopt (см. Описание shopt в разделе «Команды SHELL BUILTIN» ниже).

Так положить

shopt -s expand_aliases

в вашем сценарии.

Убедитесь, что вы установили файл псевдонимов после установки этого в вашем скрипте.

shopt -s expand_aliases
source ~/.bash_aliases
ddeimeke
источник
7
Я поместил его в свой сценарий, но он все еще не работает. Та же ошибка
Заид
5
Добавление shopt -s expand_aliases source ~/.bash_aliasesотлично работает для меня. Часто в .bashrc существует форма обнаружения интерактивной оболочки: # If not running interactively, don't do anything [ -z "$PS1" ] && return@Zaid, возможно, вы хотите проверить это в файле, который вы выбрали.
Фрэнк Шуберт
1
отлично! сохранил мои скрипты !! :) в терминале читать / искать / просматривать информацию и справочные материалы настолько сложно, что я только что давно сдался и начал искать в интернете ...
Aquarius Power
2
Любопытно, shopt -s expand_aliasesчто не нужно идти перед определением псевдонима, но перед использованием псевдонима. Добавление к @FrankSchubert: Интерактивное обнаружение оболочки также может быть выполнено с использованием $-опций, которые содержат параметры оболочки, особенно iесли оболочка является интерактивной.
действует
2
это неправильный ответ ... Источники псевдонимов внутри вашего сценария не являются ответом. Вы ~/.bash_aliasesможете зависеть от других вещей, ранее загруженных в интерактивную оболочку ... Самое близкое, что я нашел, - это изменить свой hashbang на #!/bin/bash -liВсе еще не идеально. В идеале вы должны использовать функции, а не псевдонимы.
Стефанос Каланцис
44

Псевдонимы нельзя экспортировать, поэтому они недоступны в сценариях оболочки, в которых они не определены. Другими словами, если вы определите их в, ~/.bashrcони недоступны your_script.sh(если вы не используете исходный текст ~/.bashrcв сценарии, что я бы не советовал, но есть способы сделать это правильно).

Однако функции можно экспортировать, и они будут доступны для сценариев оболочки, которые запускаются из среды, в которой они определены. Это можно сделать, поместив это в ваш bashrc:

Foo ()
{
    echo "Hello World!"
}
экспорт -f foo

Как говорится в руководстве по Bash: «Практически для любых целей функции оболочки предпочтительнее псевдонимов».

Деннис Уильямсон
источник
1
Хотя это технически не отвечает на вопрос, как вы говорите, вы можете просто заменить alias commandA=...на commandA() { ... }затем, export commandAи вы получите идентичное поведение с псевдонимом. Так что, насколько я знаю, это почти идентичная альтернатива псевдонимам, которая прекрасно работает в скриптах bash
Phylliida
Проблема здесь в том, что вам нужен псевдоним, которому вы передаете множество параметров в кавычках. например, в качестве примера, alias b=bashпозволяет легко сделать то, b -c "echo test | grep test"что было бы трудно сделать в функциях.
Fmstrat
@Fmstrat: b () { bash "$@"; }тогдаb -c "echo test | grep test"
Деннис Уильямсон
11
[cmd line] > bash -i [your script's file path]

Это iдля интерактивных и источников вашего bashпрофиля для вас.

user65576
источник
-5

Иногда я обнаружил, что bash-скрипт тоже не распознает экспорт. Тем не менее, изменив его на

#!/bin/sh

работает для меня.

lwpro2
источник
1
Нет, не ...
Хафиз Темури