Вопрос или проблема
У меня установлена alias
для команды rm
. Если я выполняю команду alias
, это то, что я получаю в качестве вывода.
alias rm='rm -i'
Теперь, когда я запускаю команду rm
, она работает нормально, как и ожидалось.
rm ramesh
rm: удалить обычный пустой файл `ramesh'? y
Теперь я изучал системные вызовы, которые выполняются, когда я запускаю команду. Для этого я узнал про команду strace
из здесь, которая перечисляет файлы, к которым происходит обращение при выполнении команды. Команда следующая.
strace -ff -e trace=file rm ramesh 2>&1
Команда работает отлично, за исключением того, что она игнорирует мои alias, которые у меня установлены для команды rm
. Она удаляет файл без запроса у пользователя.
Итак, игнорирует ли strace
alias таким образом? Если да, то почему?
РЕДАКТИРОВАНИЕ:
Не уверен, связано ли это как-то, но type -a rm
дает мне следующий вывод:
rm is aliased to `rm -i'
rm is /bin/rm
Итак, рассматривается ли /bin/rm
в этом случае, из-за чего пользователя не запрашивают перед удалением?
strace
не выполняет rm -i
по той же причине, по которой:
echo rm
не выводит rm -i
.
Alias — это функция некоторых оболочек, позволяющая автоматически заменять одни строки другими, когда они встречаются в командной позиции.
В:
alias foo='whatever'
foo xxx
Оболочка расширяет это до:
whatever xxx
и это проходит еще одну стадию интерпретации, в данном случае приводя к выполнению команды whatever
.
Alias расширяются только тогда, когда они находятся в командной позиции (как первое слово в строке команды).
zsh
поддерживает глобальные alias.
Вы могли бы сделать:
alias -g rm='rm -i'
Но вы бы этого не захотели, так как это бы означало, что:
echo rm
выдаст rm -i
, например.
strace
использует переменную окружения PATH
для нахождения программы, которую нужно отслеживать, вместо выполнения через оболочку (что захламило бы вывод). Альяс не является программой, это функция оболочки, и поэтому strace
его игнорирует.
Запуск strace strace rm
довольно поучителен, а также представляет собой интересный рекурсивный процесс.
Alias — это функция вашей оболочки. Однако strace
выполняет команду напрямую (используя, вероятно, execve
), что не включает использование оболочки. (Если бы strace
выполнял данную команду через оболочку, то вывод strace
содержал бы все системные вызовы выполнения оболочки, а не только те, что связаны с интересующим процессом.)
Кроме того, когда вы запускаете strace rm ramesh
, интерактивная оболочка не пытается подставить ваш alias в аргументы для strace, поскольку это было бы чрезвычайно запутанно для всех. Оболочка расширяет alias только в первой позиции на линии команды.
strace
использует функцию execve c
как find command
, однако find использует exec function
. Вы не можете использовать alias
, встроенную shell-команду
и тому подобное.
Вам необходимо выполнить:
strace /bin/rm -i ramesh
Развивая ответ Стефана Шазела, если вы определите
alias strace="strace "
(с пробелом в конце), тогда команда
strace rm ramesh
будет обработана как
strace rm -i ramesh
Но даже это будет работать только для первого слова после strace
,
так что это не будет применяться напрямую к вашему примеру (где у вас есть промежуточные опции).
Но, если вы определите
alias my_strace="strace -ff -e trace=file "
то
my_strace rm ramesh
будет обработана как
strace -ff -e trace=file rm -i ramesh
Нет алиасов здесь
Предположим, у нас есть определение alias alias rm='rm -i'
в нашем ~/.bashrc
. Alias добавляет опцию для запроса перед удалением каждого файла:
$ touch ./file
$ rm ./file
/bin/rm: удалить обычный пустой файл ‘./file’?
Это не ошибка strace
, что он не использовал alias:
Это просто не связано с alias.
В команде
$ strace -f -e file -o rm.strace rm ./file
Слова rm
и ./file
пока всего лишь аргументы для strace – оболочка не может расширить alias rm
, потому что она не может знать, что strace будет использовать эти аргументы как команду позже.
В общем, алиасы команд могут использоваться только там, где команды могут быть.
Alias — это функция оболочки, а strace
вообще не использует оболочку, когда вызывает команду из командной строки. Он использует exec()
, с командами и аргументами из собственной командной строки.
Внутри strace
команда будет вызвана с чем-то вроде exec("rm", "file")
, и exec()
найдет /bin/rm
в PATH – без использования оболочки.
Явная оболочка
Теперь, почему бы не включить оболочку в команду strace
?
$ touch ./file
$ strace -f -e file -o rm.strace bash -c 'rm ./file'
$ ls ./file
ls: невозможно получить доступ к ./file: Нет такого файла или каталога
Хмм… это не сработало. rm
просто удалил файл, без запроса -i
.
Алиасы для интерактивного использования
Алиасы обычно активируются только в интерактивных оболочках, актуальных командных строках в терминале.
На нашем примере alias легко показать, почему это имеет смысл: если бы alias rm -i
расширялся в сценариях оболочки, они бы зависали на первой rm
с отсутствием кого-то, кто бы нажимал y
.
Алиасы контролируются опцией оболочки expand_aliases
. Мы могли бы установить опцию с bash +O expand_aliases -c ...
. Но этого недостаточно, потому что неинтерактивная оболочка также не будет читать ~/.bashrc
. Это означает, что наш alias не только выключен опцией, но и даже не определен.
Притворяемся интерактивными
Простым способом решения обоих вопросов является использование опции командной строки -i
, чтобы оболочка притворялась интерактивной:
$ touch ./file
$ strace -f -e file -o rm.strace bash -i -c 'rm ./file'
/bin/rm: удалить обычный пустой файл ‘./file’?
Наконец-то, был использован alias -i
!
Заметьте, что вы обычно не будете использовать оболочки, работающие с опцией -i
для сценариев, даже если вы хотите, чтобы ваши alias были доступны, например.
Ответ или решение
Когда вы используете команду strace
для отслеживания системных вызовов, связанных с выполнением команды rm
, вы сталкиваетесь с ситуацией, когда алиас на rm
игнорируется. Давайте разберёмся, почему так происходит и как это можно обойти.
Почему strace
игнорирует алиас
Алиасы — это функция оболочки, которая позволяет заменять одни команды на другие. Например, ваш алиас alias rm='rm -i'
заменяет rm
на rm -i
, добавляя интерактивный запрос на удаление файлов.
Важные моменты:
-
Алиасы только для оболочки: Алиасы работают только в контексте оболочки, т.е. они заменяют команды при непосредственном вводе пользователем в интерактивной сессии терминала. Они не распространились на другие инструменты.
-
strace
работает на уровне системных вызовов:strace
не использует оболочку для выполнения команд. Он вызывает команды напрямую с помощью системного вызоваexecve
, что обходится без интерпретации алиасов оболочкой. -
strace
и PATH: При вызове изstrace
, командаrm
ищется в переменной окруженияPATH
, где находится исполняемый файл/bin/rm
. Таким образом, никакие алиасы не применяются.
Как обойти это ограничение
Если вы хотите, чтобы команда rm -i
выполнялась даже при использовании strace
, у вас есть несколько возможностей:
-
Запуск оболочки с интерактивными настройками:
Вы можете запустить оболочку, которая будет считывать ваши алиасы и работать с ними.strace -ff -e trace=file bash -i -c 'rm ramesh'
Использование опции
-i
делает оболочку "интерактивной", что приводит к чтению.bashrc
и активации алиасов. -
Явное указание команды с опцией:
Можно передать команду с опцией напрямую вstrace
без использования алиаса:strace -ff -e trace=file /bin/rm -i ramesh
Это гарантирует, что будет вызвана именно версия команды с интерактивным удалением.
Заключение
Алиасы — это мощный инструмент для упрощения часто используемых команд, но они ограничены контекстом оболочки. При работе с более низкоуровневыми инструментами, такими как strace
, важно понимать, как работают системные вызовы и на какой уровень они влияют. Правильная конфигурация может включать использование оболочки в интерактивном режиме или явное указание опций команд. Эти подходы помогут вам достичь желаемого поведения, работая с strace
.