Вопрос или проблема
Я пытаюсь создать символические ссылки на исполняемые файлы в каталоге 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 интерпретирует значения возврата. Я пробовал с одинарными и двойными скобками, и получаю то же самое поведение.
Обновление
Мне удалось заставить это работать вот так:
RUN for i in ../src/u-boot/tools/*; do if /usr/bin/readelf -h $i | grep -q DYN; then ln -s $i .; fi; done
Проблема имеет несколько аспектов, но основной заключается в том, что вы выбрали конструкцию теста Bash [[ ... ]]
и поместили условие теста полностью в двойные кавычки. Это означает, что вся условие интерпретируется как строка, которая, так как она непустая, всегда оценивается как “истинное”.
Второй момент в том, что вам на самом деле не нужна конструкция теста. Поскольку вы основываете свой тест на наличии свойства DYN
в выводе readelf
, которое вы проверяете с помощью grep
, вы можете просто написать
if readelf -h "$i" | grep -q "DYN"
then
...
fi
Поскольку статус выхода конвейера команд является статусом последней команды в конвейере, вы получите “истинное”, если DYN
был найден в выводе, и “ложное”, если DYN
не был найден.
Последний момент может быть недопониманием значения $?
. Для тестов в оболочке код выхода 0
означает истинное
, в то время как ненулевой код означает ложное
, поэтому отрицание (if ! ....
), которое у вас было, (если я правильно понимаю ваше намерение) неверно на данный момент.
Ответ или решение
Для решения задачи определения исполняемых файлов в контексте использования readelf
и grep
необходимо учесть несколько моментов, касающихся работы с условиями в Bash и интерпретацией возвращаемых значений команд.
Проблема исходного кода
В вашем начальном коде:
for i in ../src/u-boot/tools/*; do
if ! [[ "readelf -h $i | grep -q DYN" ]]; then
ln -s $i .
fi
done
вы столкнулись с ошибкой, потому что условие, обернутое в двойные кавычки внутри [[ ... ]]
, интерпретируется как строка. Это означает, что Bash всегда считает условие истинным (всегда возвращает 0), так как непустая строка имеет значение "true", а не результат выполнения команды readelf
.
Решение с использованием if
без
Для правильного определения исполняемых файлов можно упростить код, убрав лишнюю обертку в [[ ... ]]
и сделав выполнение команд в условии:
for i in ../src/u-boot/tools/*; do
if readelf -h "$i" | grep -q "DYN"; then
ln -s "$i" .
fi
done
В этом варианте:
- Проверка на наличие "DYN": Условие проверяет, содержит ли вывод команды
readelf -h
слово "DYN". - Правильная интерпретация статусов: Так как статус выхода из
grep
будет 0, если "DYN" найден, условие будет истинным, и создастся символическая ссылка на исполняемый файл.
Возвращаемые значения
Важно помнить, что в Bash:
- Статус 0 указывает на успешное выполнение (что соответствует "true").
- Статус, отличный от 0, указывает на неудачу (что соответствует "false").
Следовательно, использование if ! ...
в вашем исходном коде было ошибочным, так как вы имели в виду, что вы хотите выполнить действия, когда не найден "DYN".
Итоговая рекомендация
Постарайтесь привязаться к простоте и понятности. Следующий рабочий фрагмент кода выполнит необходимую задачу, корректно проверяя исполняемые файлы и создавая символические ссылки только для них:
for i in ../src/u-boot/tools/*; do
if readelf -h "$i" | grep -q "DYN"; then
ln -s "$i" .
fi
done
Используя данный подход, вы сможете успешно идентифицировать исполняемые файлы и упростить процесс создания символических ссылок в вашем Docker скрипте.