Почему bash дает следующий результат после расширения фигурных скобок?

Вопрос или проблема

Я использую Linux и следующую версию bash:

GNU bash, версия 5.1.16(1)-release (x86_64-pc-linux-gnu)

Когда я набираю:

echo file{[1,2],3}.txt

Я ожидаю, что сначала выполнится раскрытие скобок, так что:

echo file[1,2].txt file3.txt

После этого я ожидаю, что на этом все и закончится, так как [1,2] не является допустимой глобой. Однако, в итоге выводится следующее:

file[1.txt file2].txt file3.txt

Почему?

Список файлов в текущем каталоге (результат команды ls):

go.mod  hello.sh  hi  main.go

Потому что вы так и указали 🙂 Вот что видит bash:

file{[1,2],3}.txt

Символы [ и ] не имеют специального значения в этом контексте, глобусы не разворачиваются внутри раскрытий скобок: если раскрытие скобок приводит к созданию глоба, то этот глоб будет обработан оболочкой после раскрытия скобок.

Таким образом, здесь происходит следующее: оболочка видит три элемента, разделенных запятыми, в скобках: [1, 2] и 3. Вот почему она должным образом выводит file[1.txt, file2].txt и file3.txt. Это не отличается от использования чего-то вроде file{a,b,c}.txt.

Вы можете увидеть это с помощью set -x:

$ set -x
$ echo file{[1,2],3}.txt
+ echo 'file[1.txt' 'file2].txt' file3.txt
file[1.txt file2].txt file3.txt

Это поведение задокументировано в разделе EXPANSIONS руководства man bash, где дана последовательность обработки:

Порядок раскрытий: раскрытие скобок; раскрытие тильды, раскрытие параметров и переменных, арифметическое раскрытие и подстановка команды (выполняющиеся слева направо); разделение слов; и раскрытие путей.

Кстати, [1,2] является вполне допустимым шаблоном для глоба, он просто не раскрывается внутри скобок. Например:

$ touch file{1,2,3}.txt
$ ls
file1.txt  file2.txt  file3.txt
$ ls file[1,2].txt
file1.txt  file2.txt

Заметьте, что в глобах [a,b] соответствует любому из символов a, , или b. Это не значит “a или b”.

Ответ или решение

Теория:

Bash является одним из наиболее популярных интерпретаторов командной строки в системах на базе Unix и Linux. Одной из важных функций в bash является расширение скобок (brace expansion), которая позволяет значительно ускорить работу с файлами и директориями, создавая несколько вариантов строки согласно заданным паттернам. Однако, понимание того, как работает это расширение, особенно в сочетании с другими механизмами bash, такими как глоббинг (pathname expansion) и расширение слова (word splitting), является ключом к правильной интерпретации команд и предсказанию их результата.

Например, команда echo file{[1,2],3}.txt показывает интересный способ работы bash с расширением скобок. Основной момент заключается в том, что внутри фигурных скобок {} выражение разбивается по запятым, а не по логическим блокам "или", как это часто интерпретируется. Это означает, что bash разбивает содержимое на три элемента: [1, 2] и 3. После этого создается комбинация строк: file[1.txt, file2].txt и file3.txt.

Пример:

Чтобы лучше понять, как работает эта команда, рассмотрим ее пример пошагово:

  1. Исходная команда: echo file{[1,2],3}.txt.
  2. Bash выполняет расширение скобок, интерпретируя элементы внутри {} как отдельные строки, разделенные запятыми. Следовательно, происходит разделение на: file[1.txt, file2].txt и file3.txt.
  3. Каждая из этих строк становится аргументом для команды echo.

Кроме того, важно понимать порядок выполнений различных расширений в bash. Согласно документации man bash, расширение скобок происходит в первую очередь, перед такими операциями как tilde expansion, параметрическое и переменное расширение, арифметическое расширение и командное замещение. Понимание этого порядка критично при сложных операциях, поскольку оно определяет последовательность обработки данных.

Применение:

Теперь, когда мы поняли, как функционирует расширение скобок в bash, можем рассмотреть конкретные случаи его использования. Например, если ваша задача заключается в перечислении файлов или создании нескольких копий файла с различными именами, это поможет автоматизировать процесс. Однако необходимо внимательно следить за тем, как bash разбивает содержимое внутри фигурных скобок и как это соотносится с глоббингом.

На практике, если вам нужно для каждого из элементов [1,2] создать отдельный файл или просто вывести имя, команда должна быть скорректирована для правильной обработки глоббинга:

touch file1.txt file2.txt file3.txt
echo file{1..2}.txt file3.txt

Это приведет к:

file1.txt file2.txt file3.txt

Таким образом, file{1..2}.txt расширяется до file1.txt file2.txt, что соответствует ожидаемому набору файлов.

Но если ваша цель — сокрытие внутри скобок, например file[1,2].txt, вам необходимо понимать, как использовать глоббинг через наличие прямых скобок в итоговом выражении:

ls file[1,2].txt

Это будет искать файлы file1.txt и file2.txt, и они должны существовать в текущей директории для успешного выполнения команды.

Таким образом, знать и понимать детали работы механизма расширений в bash является важной частью работы ИТ-специалиста. От точного понимания работы этого инструмента зависит безопасность и эффективность автоматизации в Linux-системах. Уверенное владение и опыт работы с ним могут значительно оптимизировать процессы управления файлами и улучшить работу в командной строке, что особенно важно при управлении сложными скриптами и системами.

Оцените материал
Добавить комментарий

Капча загружается...