#linux #bash #shell #operators #ksh
#linux #bash #оболочка #операторы #ksh
Вопрос:
Я пытаюсь работать с существующей библиотекой кода, но столкнулся с проблемой. Короче говоря, я выполняю сценарий оболочки (назовем его так A
), первым действием которого является вызов другого script ( B
) . Скрипт B
находится в моем текущем каталоге (требование программы, которую я использую). В руководстве по программному обеспечению содержится ссылка на bash
, однако комментарии A
предполагают, что оно было разработано ksh
в. bash
До сих пор я работал.
Внутри A
строка для выполнения B
просто:
. B
Для вызова программы используется синтаксис «пробела через точку». Он не делает ничего необычного, например sudo
.
Когда я вызываю A
синтаксис без пробелов, т.е.:
./A
он всегда выдает ошибку, говоря, что не может найти файл B
. Я добавил pwd
, ls
, whoami
, echo $SHELL
, и echo $PATH
строки в A
для отладки и подтвердил, что B
это действительно так, скрипт выполняется с тем же $SHELL
, что и я, в командной строке, скрипт является тем же пользователем, что и я, и у скрипта тот же путь поиска $PATH
, что и у меня. Я также проверил, делаю ли я:
. B
в командной строке это работает просто отлично. Но, если я изменю синтаксис внутри A
на:
./B
вместо этого then A
выполняется успешно.
Аналогично, если я выполняю A
синтаксис с пробелом в точке, тогда оба . B
и ./B
работают.
Подведение итогов:
./A
работает только в том случае, если A
содержит ./B
синтаксис.
. A
работает A
с синтаксисом ./B
или . B
.
Я понимаю, что использование синтаксиса с пробелом в точках (т. Е. . A
) Выполняется без перехода к подоболочке, но я не понимаю, как это может привести к поведению, которое я наблюдаю, учитывая, что файл явно находится прямо там. Есть ли что-то, чего мне не хватает в нюансах синтаксиса или рабочих пространств родительских / дочерних процессов? Магия?
UPDATE1: добавлена информация, указывающая на то, что сценарий, возможно, был разработан в ksh
, пока я использую bash
.
UPDATE2: добавлена проверка для проверки $PATH
того же.
ОБНОВЛЕНИЕ3: Сценарий говорит, что он был написан для ksh
, но он выполняется bash
. В ответ на ответ Кенстера я обнаружил, что запуск bash -posix
затем . B
завершается ошибкой в командной строке. Это указывает на то, что разница в средах между командной строкой и сценарием заключается в том, что последний выполняется bash
в режиме, совместимом с POSIX, тогда как командная строка — нет. Присмотревшись немного ближе, я вижу это на bash
man
странице:
При вызове как sh bash переходит в режим posix после чтения файлов запуска.
Действительно, shebang
for A
#!/bin/sh
.
Таким образом, когда я запускаю A
синтаксис без пробелов, он разветвляется на свою собственную подоболочку, которая находится в режиме, совместимом с POSIX, потому shebang
что is #!/bin/sh
(вместо, например, #!/bin/bash
. Это критическое различие между средами выполнения командной строки и скриптов, которое приводит к A
невозможности поиска B
.
Комментарии:
1.Является
B
ли исполняемый файл?. B
технически это неexecute
B
sources
так. Если один из них естьksh
, попробуйте использоватьksh yourscript
2. Да,
B
является исполняемым. Я не совсем понимаю разницу между ними, сейчас прочитаю.3. Неважно, я вижу
source
, что это термин (и команда) для запуска чего-либо в той же оболочке.
Ответ №1:
Давайте начнем с того, как работает путь к команде и когда он используется. Когда вы выполняете команду типа:
ls /tmp
ls
Здесь нет символа /, поэтому оболочка ищет каталоги в вашем командном пути (значение переменной среды PATH) для файла с именем ls
. Если он находит один, он выполняет этот файл. В случае ls
с, это обычно /bin
или /usr/bin
, и оба этих каталога обычно находятся в вашем path .
Когда вы выполняете команду с / в командном слове:
/bin/ls /tmp
Оболочка не выполняет поиск пути к команде. Он специально ищет файл /bin/ls
и выполняет его.
Запуск ./A
— это пример выполнения команды с / в ее имени. Командная оболочка не ищет путь к команде; она специально ищет файл с именем ./A
и выполняет его. «.» является сокращением для вашего текущего рабочего каталога, поэтому ./A
ссылается на файл, который должен быть в вашем текущем рабочем каталоге. Если файл существует, он выполняется как любая другая команда. Например:
cd /bin
./ls
будет работать для запуска /bin/ls
.
Запуск . A
является примером поиска файла. Исходный файл должен быть текстовым файлом, содержащим команды оболочки. Он выполняется текущей оболочкой без запуска нового процесса. Файл, который должен быть получен, находится таким же образом, как и команды. Если имя файла содержит /, то оболочка считывает конкретный файл, который вы назвали. Если имя файла не содержит /, то оболочка ищет его в пути к команде.
. A # Looks for A using the command path, so might source /bin/A for example
. ./A # Specifically sources ./A
Итак, ваш скрипт пытается выполнить . B
и завершается неудачно, утверждая, что B
он не существует, хотя B
в вашем текущем каталоге есть файл с именем прямо там. Как обсуждалось выше, оболочка искала бы ваш путь к команде B
, потому B
что не содержит символов / . При поиске команды оболочка не выполняет автоматический поиск в текущем каталоге. Поиск выполняется только в текущем каталоге, если этот каталог является частью пути к команде.
Короче говоря, . B
вероятно, происходит сбой, потому что у вас нет «.» (текущий каталог) в вашем командном пути, и сценарий, который пытается получить исходный B
код, предполагает, что «.» является частью вашего пути. На мой взгляд, это ошибка в скрипте. Многие люди работают без «.» на своем пути, и сценарий не должен зависеть от этого.
Редактировать:
Вы говорите, что скрипт использует ksh
, пока вы используете bash
. Ksh следует стандарту POSIX — фактически, KSH был основой для стандарта POSIX — и всегда ищет путь к команде, как я описал. Bash имеет флаг под названием «режим POSIX», который определяет, насколько строго он соответствует стандарту POSIX. Когда он не находится в режиме POSIX — именно так люди обычно его используют — bash проверит текущий каталог на наличие исходного файла, если он не найдет файл в пути к команде.
Если вы должны были запускать bash -posix
и запускать . B
в этом экземпляре bash, вы должны обнаружить, что это не сработает.
Комментарии:
1. Вы правы в том, что текущий каталог отсутствует
$PATH
. Я думал об этом, но тогда почему это. B
работает в командной строке? Я попробовалecho $PATH
, и это то же самое как в сценарии, так и в моем. Это настоящая суть моего вопроса: почему сценарий завершается с ошибкой, когда командная строка завершается успешно, Если похоже, что все (оболочка, переменные среды и т. Д.) Одинаковы?2. Да, сбой
bash -posix
. Я вернулся назад и выяснил, почему скрипт работает в режиме, совместимом с POSIX, и добавил полное объяснение к исходному вопросу (здесь не подходит).3. Возможно, также объясните, что поиск файла в текущем процессе означает, что исходный файл может манипулировать вашей средой. Поэтому, если вы запустите
. B
иB
выполняетеfoo=bar
, тогда эта переменная будет установлена поB
завершении, пока текущий сценарий или интерактивная оболочка не завершатся, тогда./A
как вы не можете изменить свои переменные (подпроцесс не может изменить своего родителя).