Bash shadow a command - функция с тем же именем, что и команда [duplicate]

No tengo una forma elegante de eliminar estos dispositivos que no sea forzar la eliminación del módulo v4l2loopback:

sudo modprobe -r v4l2loopback
7
10.07.2018, 22:18
3 ответа

Проблема в том, что первые два варианта предназначены только для работы с псевдонимами. Это не специальные операторы перенаправления, которые могут определить, есть ли у вас функция или команда с таким же именем. Все, что они делают, — это предотвращают расширение, что и пытается сделать псевдоним

.
alias v='sudo vim'
v x.txt
#automatically expands "v" to "sudo vim" and then does the rest of the command
# v x.txt ==> sudo vim x.txt

Bash просто пытается расширить первое слово команды, используя список известных ему псевдонимов (, который вы можете получить с помощьюalias). Псевдонимы не принимают аргументов и могут быть разделены только первым словом (пробелом -;vim x.txtне будет расширяться в sudo vimim x.txtс использованием псевдонима выше )в команде для правильного расширения.

Однако раскрытие никогда не происходит с объектами в одинарных кавычках.:echo '$USER'выведет литерал $USER, а не то, что обозначает переменная. Кроме того, bash расширяет \xдоx(в основном ). Они не добавляются -специально для того, чтобы избежать псевдонима, они просто часть того, как было написано расширение bash. Таким образом, вы можете использовать эти методы, чтобы позволить псевдониму скрывать команду и по-прежнему иметь доступ к фактической команде.

alias ls='ls -la'
ls foo.txt     #will expand into ls -la foo.txt
\ls foo.txt    #will expand into ls foo.txt
'ls' foo.txt   #same as above
'ls foo.txt'   #same as above

Однако они не останавливают функции. Функция не нуждается в расширении для работы, она вызывается по своему имени.

ls () {
    echo "not an alias"
}
alias ls='echo "an alias"'

ls foo.txt          #will echo "an alias"
\ls foo.txt         #will echo "not an alias"
'ls' foo.txt        #will echo "not an alias"
command ls foo.txt  #will actually run `ls`
10
28.04.2021, 23:44

Если функция вызывает полный путь к двоичному файлу vim, вы не получите рекурсивный цикл. Кроме того, использование параметра -Hдля sudo устанавливает $HOME.

vim() {
    if [ -w "$1" ]; then
        command vim "$1"
    else
        sudo env HOME="$HOME" \vim -u ~/.vimrc "$1"
    fi
}

Спасибо. Я не думал об этом, но теперь он есть и у меня в .bashrc.


ОТРЕДАКТИРОВАНО:обновлены вызовы command vimи sudo envвместо sudo -h. таким образом, нет петли, в которой можно было бы оставаться.

2
28.04.2021, 23:44

Why do the other options not work as I would expect them to?

Потому что в способе выполнения командной строки есть некоторые особенности.

Основная концепция заключается в том, что первое слово командной строки — это команда, которую оболочка будет искать и пытаться выполнить в следующем порядке:

  1. Командная строка разбита на метасимволы (в основном):

    metacharacters
    A character that, when unquoted, separates words. One of the following:
    | & ; ( ) < > space tab newline

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

    $ alias ls='ls -la'
    $ ls dir               # will expand to `ls -la dir`
    

    Обратите внимание, что :Если последний символ значения псевдонима является пробелом, то следующее командное слово, следующее за псевдонимом, также проверяется на расширение псевдонима.

  3. Если (результирующее )первое слово является расширением (подобно $var), оно заменяется (и подлежит разбиению на слова IFS (и подстановке подстановки ), если оно не заключено в кавычки):

    $ var='echo -e '
    $ $var test '\twords'            # will expand to `echo -e test words`
    test    words
    
  4. Результирующее первое слово после описанных выше расширений (после присвоения необязательных переменных )будет искаться в этом порядке:

    • специальные встроенные функции (только в режиме POSIX)
    • функции
    • встроенные
    • хешированные команды (чтение справки хэш)
    • внешние команды (поиск в $PATHкаталогах)

    Будет выполнено первое найденное совпадение.

Порядок может быть изменен (для теста):

  • Чтобы обойти только псевдоним, используйте \testили любое другое расширение.
  • Чтобы игнорировать функции и псевдонимы, используйте command test.
  • Чтобы выполнить встроенную функцию, используйте builtin test.
  • Чтобы выполнить внешнее приложение, используйте явный путь:/bin/test.

Итак, функция, определенная как:

$ ls(){ ls; }

Будет вызываться в бесконечном цикле. Как и скрипт, который вызывает одно и то же первое слово.Что-то вроде:

#!/bin/bash
$0 "$@"

Повторно -будет выполнять один и тот же сценарий в цикле до тех пор, пока ядро ​​не выйдет из строя (, если используемое ядро ​​имеет ограничение на количество последовательных вызовов сценариев ).

Порядок будет показан при запускеtype -a:

$ test(){ echo test function; }
$ alias test=test
$ type -a
test is aliased to `test'
test is a function
test ()
{
    echo test function
}
test is a shell builtin
test is /usr/bin/test

Функция (, определенная в вопросе ), будет обходить только псевдоним с \vim, но не функцию. Чтобы обойти псевдоним и функции, используйте команду. Эта функция должна делать то, что вам нужно:

vim() {
        if [ -w "$1" ]; then
            command vim "$1"
        else
            sudo HOME="$HOME" bash -c 'command vim "$@"' _ -u ~/.vimrc "$1"
        fi
      }
4
28.04.2021, 23:44

Теги

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