Усовершенствованный аргумент: как сбежать с находками, ксаргами и вложенными командами

Проблемы при использовании find и xargs

Когда вы работаете с утилитами командной строки в Linux, такими как find и xargs, вы можете столкнуться с проблемами, связанными с "странными" именами файлов. Одной из распространенных ситуаций является передача имен файлов, содержащих символы, которые чувствительны к оболочке. Например, символы вроде ', ", `, и ( могут вызывать ошибки.

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

Пример проблемы

Рассмотрим следующий сценарий:

mkdir remove_afterwards
touch remove_afterwards/"some [\"strange\"] ('file')" 

find remove_afterwards/ -type f -print0 | xargs -0 -I{} sh -c 'echo "{}" $(stat -c "%s" "{}")'

В этом случае, попытка вывести как имя файла, так и его размер с помощью stat вызывает ошибку:

stat: cannot statx 'remove_afterwards/some [strange] ('\''file'\'')': No such file or directory

При этом, если вы используете команду без вложенного вызова, она может работать:

find remove_afterwards/ -type f -print0 | xargs -0 -I{} sh -c 'echo "{}"'

Анализ проблемы

Эта проблема возникает из-за того, что sh -c не может правильно интерпретировать аргумент, когда он расширяется с использованием {} внутри кода оболочки. sh получает расширенный аргумент и интерпретирует его как код оболочки, что приводит к нестабильному поведению.

Решение проблемы

Безопасный способ решения этой проблемы — передать расширенный {} как отдельный аргумент, который будет использоваться в качестве позиционного параметра в sh -c. Пример корректного синтаксиса:

find remove_afterwards/ -type f -print0 | xargs -0 -I{} sh -c 'echo "$1" "$(stat -c "%s" "$1")"' find-sh {}

В этом примере find-sh — это просто идентификатор, который позволяет sh -c корректно обрабатывать параметры.

Объяснение решения

Преимущество такого подхода в том, что код в sh -c остается статическим, и расширяемый {} передается как позиционный параметр $1. Это значит, что интерпретатор знает, что это не код, а просто значение. Важно правильно заключать $1 в кавычки, чтобы избежать проблем с пробелами и специальными символами.

Углубление в тему

Аналогичная проблема также возникает при использовании find -exec. Всегда рекомендуется придерживаться статического кода оболочки, если возможно, а не вставлять расширяемые значения. Это уменьшает риск внедрения нежелательного кода.

# Неправильный способ
var="I want to print '$(beep)'"
sh -c "echo '$var'"

# Правильный способ
var="I want to print '$(beep)'"
sh -c 'echo "$1"' sh "$var"

Рекомендации

Если вы планируете написать статический код в sh -c, советую оборачивать всю строку в одинарные кавычки. Это поможет избежать многих проблем, связанных с интерпретацией специальных символов. Помните, что наилучший подход — всегда минимизировать динамическое использование кода оболочки, чтобы свести к минимуму риски.

Источник

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *