Вопрос или проблема
Я пытаюсь создать символическую ссылку на исполняемые файлы в директории bin внутри docker-скрипта. Мне нужен способ идентифицировать исполняемые файлы и вернуть булевый статус. Я пробовал это. Это не работает, и я не понимаю, почему.
for i in ../src/u-boot/tools/*; do if ! [[ "readelf -h $i | grep -q DYN" ]]; then ln -s $i .; fi; done
Если я посмотрю на фактические возвращаемые значения, я увижу ожидаемые значения:
root@0f1bca692c90:/home/work/bin# readelf -h ../src/u-boot/tools/mkimage |grep -q DYN
root@0f1bca692c90:/home/work/bin# echo $?
0
root@0f1bca692c90:/home/work/bin# readelf -h ../src/u-boot/tools/mkimage.c |grep -q DYN
readelf: Error: Not an ELF file - it has the wrong magic bytes at the start
root@0f1bca692c90:/home/work/bin# echo $?
1
Я предполагаю, что неправильно понимаю, как bash интерпретирует возвращаемые значения. Я пробовал с одинарными и двойными скобками, и поведение остается тем же.
Проблема имеет несколько аспектов, но основной из них заключается в том, что вы выбрали конструкцию теста Bash [[ ... ]]
и поместили условие теста полностью в двойные кавычки. Это означает, что все условие интерпретируется как строка, которая, будучи непустой, всегда оценивается как “истина”.
Второй момент заключается в том, что вам на самом деле не нужна конструкция теста. Поскольку вы основываете свой тест на наличии свойства DYN
в выводе readelf
, который вы проверяете с помощью grep
, вы можете просто указать
if readelf -h "$i" | grep -q "DYN"
then
...
fi
Так как код выхода конвейера команд – это код последней команды в конвейере, вы получите “истину”, если DYN
был найден в выводе, и “ложь”, если DYN
не был найден.
Последний момент может быть заблуждением относительно значения $?
. Для тестов оболочки код выхода 0
означает истину
, а ненулевой означает ложь
, поэтому отрицание (if ! ....
), которое вы использовали, (если я правильно понимаю ваше намерение) неправильно на данном этапе.
Ответ или решение
Для выполнения задачи по определению, является ли файл исполняемым, и возвращению булевого значения в скрипте Docker, необходимо учитывать несколько ключевых аспектов, касающихся работы с Bash и командой readelf
. Ваша первоначальная попытка имеет несколько недостатков, которые необходимо исправить для достижения желаемого результата.
Проблема в коде
В приведённом вами коде имеется ошибка в использовании конструкции [[ ... ]]
, которая неправильно интерпретируется из-за размещения команды readelf
внутри двойных кавычек. Это приводит к тому, что Bash воспринимает условие как строку, которая всегда возвращает истину (true).
Исходный код
for i in ../src/u-boot/tools/*; do
if ! [[ "readelf -h $i | grep -q DYN" ]]; then
ln -s $i .
fi
done
Как правильно реализовать проверку
Для корректной реализации проверки, лучше всего воспользоваться напрямую выполнением команды readelf
, вместо обрамления её в конструкцию [[ ... ]]
. Это обеспечит правильную обработку возвращаемых кодов завершения команд. Попробуйте следующий вариант кода:
for i in ../src/u-boot/tools/*; do
if readelf -h "$i" | grep -q "DYN"; then
# Ссылка на исполняемый файл (файл, который мы хотим сохранить)
ln -s "$i" .
fi
done
Объяснение работы кода
- Цикл for: Итерирует по всем файлам в директории
../src/u-boot/tools/
. - Команда readelf: Получает заголовок файла и передаёт его на обработку
grep
. - Проверка с помощью grep: Если в выводе есть строка
DYN
, командаgrep
возвращает 0 (true). - Создание символической ссылки: Если условие истинно, создаётся символическая ссылка на нужный файл.
Понимание возвращаемых кодов
Важно помнить, что в Unix-подобных системах:
- Код завершения
0
указывает на успешное выполнение операции (true). - Код завершения
1
или любой другой ненулевой код говорит о неуспешном выполнении (false).
Заключение
Таким образом, вы сможете успешно определить, является ли файл исполняемым и эффективно создать символическую ссылку на него в нужной директории. Приведённое выше решение является оптимальным и правильно использует средства Bash для выполнения поставленной задачи. Убедитесь, что у вас есть соответствующие права на выполнение команд в Docker-контейнере, чтобы избежать проблем с доступом.