Может показаться, что prefix-*
должен легко превращаться, например, в prefix-1 prefix-2
, поскольку мы привыкли видеть отсортированные списки каталогов. Но оказывается, что очень немногие файловые системы могут фактически создавать отсортированные списки имен файлов, и, кроме того, что не существует стандартного API для запроса отсортированных списков имен файлов.
Если программе - такой как ls
, или, в этом отношении, bash
- нужен список имен файлов, ей нужно прочитать весь список каталогов, который будет создан в некотором случайном порядке (часто порядок связан со временем создания иногда оно основано на хэше имени файла, но ни в коем случае это не простой алфавитный порядок). Таким образом, чтобы разрешить prefix-*
, вам нужно прочитать весь каталог и проверить каждое имя файла по шаблону. Поскольку наиболее дорогостоящей частью этой процедуры является чтение каталога, не имеет значения, насколько сложен шаблон или сколько имен файлов соответствуют шаблону.
Таким образом, расширение пути ("решение глобусов") будет медленным в большом каталоге. Это причина избегать больших каталогов, а не причина избегать глобусов.
Но есть еще один важный пункт данных: prefix-{1,2}
не является расширением пути. Это « расширение скобок » и расширение стандарта оболочки Posix (хотя его реализуют почти все оболочки). Существует ряд различий между расширением фигурных скобок и расширением пути, но одно важное и важное различие заключается в том, что расширение фигурных скобок не зависит от существования файлов. Разбивка скобок - это простая строковая операция.
Следовательно, prefix-{1,2}
всегда будет расширяться до prefix-1 prefix-2
, независимо от того, существуют эти файлы или нет. Это означает, что он может быть расширен без чтения каталога и без stat
какого-либо файла. Понятно, что это будет быстро. Но есть и обратная сторона: невозможно определить, соответствует ли результат реальным файлам.
Рассмотрим следующий простой пример:
$ mkdir test && cd test
$ touch file1 file2 file4
$ ls file*
file1 file2 file4
$ ls file[1234]
file1 file2 file4
$ ls file{1,2,3,4}
ls: cannot access file3: No such file or directory
file1 file2 file4
Конечная точка: расширение имени пути выполняется оболочкой, а не ls
. С расширением пути мы могли бы также использовать echo
:
$ echo file*
file1 file2 file4
$ echo file[1234]
file1 file2 file4
И echo
будет производить список несколько быстрее, потому что все echo
нужно сделать , это печатать свои аргументы, а ls
(который принимает те же аргументы) должен stat
каждый аргумент для того , чтобы убедиться , что это файл. Эта stat
- которая не является дешевым вызовом - полностью избыточна в случае расширения пути, потому что оболочка уже использовала список каталогов для фильтрации списка файлов и, следовательно, известно, что каждое имя файла, переданное в ls
, существует , (Если глобус не совпадал ни с одним файлом.)
Кроме того, echo является встроенным в bash
, поэтому его можно вызывать без создания дочернего процесса.
В случае расширения скобок, однако, echo
не дает тот же результат:
$ echo file{1,2,3,4}
file1 file2 file3 file4
Таким образом, мы могли бы использовать ls
, перенаправляя вывод ошибок в область битов:
$ ls file{1,2,3,4}
file1 file2 file4
и в этом случае вызовы stat
не являются избыточными, потому что оболочка никогда не проверяла имена файлов.
Если ваши каталоги не очень большие, ничего из этого не будет иметь большого значения, и глоб будет намного легче писать. Если ваши каталоги действительно огромны, вы должны рассмотреть возможность разделения их на более мелкие поддиректории.
Например, вместо путей вроде:
/var/log/remote/serverX.domain.local/ps/ps2.log.2014-mm-dd.gz
Вы могли бы использовать:
/var/log/remote/serverX/domain.local/ps/ps2.log.2014-mm-dd-gz
И если вы храните журналы вечно, вы можете извлечь год, чтобы избежать бесконечно увеличивающегося размера каталога:
/var/log/remote/2014/serverX/domain.local/ps/ps2.log.2014-mm-dd-gz
(2014
намеренно повторяется.)
Разделение каталогов, как правило, будет большой победой, поскольку оно обеспечивает механизм для оптимизации глобализации. Как уже упоминалось выше, оболочка не может оптимизировать
/var/log/remote/server[2357].domain.local/ps/ps2.log.2014-10-*-gz
но это может оптимизировать
/var/log/remote/server[2357]/domain.local/ps/ps2.log.2014-10-*-gz
Во втором случае server[2357]
нужно сопоставлять только с именами каталогов, и как только это будет сделано, ps2.log.2014-10-*-gz
нужно сопоставлять только с именами файлов в сопоставленных каталогах.