$ tree /tmp/test
/tmp/test
├── dir_a
│ ├── dir a\012file with CR
│ ├── dir a file with spaces
│ └── sub a directory
│ └── with a file in it
├── dir_b
│ ├── dir b\012file with CR
│ └── dir b file with spaces
├── dir_c
│ ├── \012
│ ├── dir c\012file with CR and *
│ └── dir c file with space and *
├── file_1
├── file_2
└── file_3
4 directories, 11 files
(ЗДЕСЬ приведен сценарий для этого. \012 — это \n, чтобы сделать сценарий более сложным. Существует .hidden тоже там.)
Похоже, существуют существенные различия в реализации рекурсивного подстановки между Bash 5.1, zsh 5.8, Python pathlib 5.10, модулем Python glob с включенной рекурсией и Ruby 3.0.< /p>
Это также предполагает, что shopt -s globstar с Bash и cwd является текущим рабочим каталогом и для этого примера установлено значение /tmp/test.
p>
Вот что делает Bash:
# no shebang - execute with appropriate shell
# BTW - this is how you count the result since ls -1 ** | wc -l is incorrect
# if the file name has \n in it.
cd /tmp/test || exit
[ -n "$BASH_VERSION" ] && shopt -s globstar
[ -n "$ZSH_VERSION" ] && setopt GLOBSTARSHORT # see table
dc=0; fc=0
for f in **; do # the glob there is the only thing being changed
[ -d "$f" ] && (( dc++ ))
[ -f "$f" ] && (( fc++ ))
printf "%d, %d \"%s\"\n" $dc $fc "$f"
done
printf "%d directories, %d files" $dc $fc
Результаты (выраженные в виде X, Y для каталогов X и файлов Y для этого примера каталога с использованием указанного glob. Проверив или запустив эти сценарии, вы можете увидеть, что посещает glob. ):
dc=fc=0
Dir.glob("/tmp/test/**/").
each{ |f| p f; File.directory?(f) ? dc=dc+1 : (fc=fc+1 if File.file?(f)) }
puts "#{dc} directories, #{fc} files"
Поэтому единственными глобусами, с которыми все согласны (кроме скрытого файла), являются *, **/* и */**/* Документация:
Bash:
< em>два соседних символа '*, используемые как один шаблон, будут соответствовать всем файлам и нолю или более каталогам и подкаталогам.
zsh: a) setopt GLOBSTARSHORT устанавливает **.c эквивалентным **/*.c и b) '**/' эквивалентен '(*/)#'; обратите внимание, что это соответствует файлам как в текущем каталоге, так и в подкаталогах.
pathlib: ** что означает «этот каталог и все подкаталоги рекурсивно»
python glob: если рекурсивно установлено значение true, шаблон ** будет соответствовать любым файлам и нулю или более каталогов, подкаталогов и символических ссылок на каталоги. Если за шаблоном следует os.sep или os.altsep, файлы не будут совпадать.
ruby: ** Сопоставляет каталоги рекурсивно, если за ними следует /. Если этот сегмент пути содержит какие-либо другие символы, он аналогичен обычному *.
Вопросы:
Правильны ли мои предположения о том, что должен делать каждый шарик?
Почему Bash — единственный рекурсивный инструмент с **? (если вы добавите setopt GLOBSTARSHORT в zsh, результат будет аналогичен **
Is разумно сказать себе, что **/* работает для всех
Предположим, у вас есть такое дерево каталогов: [code]$ tree /tmp/test /tmp/test ├── dir_a │ ├── dir a\012file with CR │ ├── dir a file with spaces │ └── sub a directory │ └── with a file in it ├── dir_b │ ├── dir b\012file with CR │ └── dir b file with spaces ├── dir_c │ ├── \012 │ ├── dir c\012file with CR and * │ └── dir c file with space and * ├── file_1 ├── file_2 └── file_3
4 directories, 11 files [/code] (ЗДЕСЬ приведен сценарий для этого. \012 — это \n, чтобы сделать сценарий более сложным. Существует .hidden тоже там.) Похоже, существуют существенные различия в реализации рекурсивного подстановки между Bash 5.1, zsh 5.8, Python pathlib 5.10, модулем Python glob с включенной рекурсией и Ruby 3.0.< /p> Это также предполагает, что shopt -s globstar с Bash и cwd является текущим рабочим каталогом и для этого примера установлено значение /tmp/test. p> Вот что делает [b]Bash[/b]: [list] [*][code]*[/code] Только файлы и каталоги в cwd. т.е. 3 каталога, 3 файла [*][code]**[/code] Все файлы и каталоги в дереве, корнем которых является cwd, но не cwd — файлы 4 и 11 [*][code]**/[/code] Только каталоги в дереве, корнем которых является cwd, но не включая cwd – 4 и 0 [*][code]*/**[/code] Все каталоги в cwd и все файлы, КРОМЕ файлов в cwd — 4 и 8 файлов, поскольку рекурсия запускается только в подкаталогах [*][code]**/*[/code] То же, что ** – 4 и 11 [*][code]**/*/[/code] Только каталоги в дереве — 4 и 0 файлов [*][code]*/**/*[/code] Только каталоги ниже второго уровня и файлы ниже первого — 1 и 8. [/list] Если я запущу этот скрипт в Bash 5.1 и zsh 5.8, они результаты разные: [code]# no shebang - execute with appropriate shell # BTW - this is how you count the result since ls -1 ** | wc -l is incorrect # if the file name has \n in it. cd /tmp/test || exit [ -n "$BASH_VERSION" ] && shopt -s globstar [ -n "$ZSH_VERSION" ] && setopt GLOBSTARSHORT # see table dc=0; fc=0 for f in **; do # the glob there is the only thing being changed [ -d "$f" ] && (( dc++ )) [ -f "$f" ] && (( fc++ )) printf "%d, %d \"%s\"\n" $dc $fc "$f" done printf "%d directories, %d files" $dc $fc [/code] Результаты (выраженные в виде X, Y для каталогов X и файлов Y для этого примера каталога с использованием указанного glob. Проверив или запустив эти сценарии, вы можете увидеть, что посещает glob. ):
‡ Число каталогов, равное 5, означает, что также возвращается CWD. † Pathlib Python сохраняет скрытые файлы; остальные нет. Сценарий Python: [code]from pathlib import Path import glob
tg="**/*" # change this glob for testing
fc=dc=0 for fn in Path("/tmp/test").glob(tg): print(fn) if fn.is_file(): fc=fc+1 elif fn.is_dir(): dc=dc+1
puts "#{dc} directories, #{fc} files" [/code] Поэтому единственными глобусами, с которыми все согласны (кроме скрытого файла), являются *, **/* и */**/* [b]Документация:[/b] [list] [*]Bash: < em>два соседних символа '*, используемые как один шаблон, будут соответствовать всем файлам и нолю или более каталогам и подкаталогам.
[*] zsh: a) setopt GLOBSTARSHORT устанавливает **.c эквивалентным **/*.c и b) '**/' эквивалентен '(*/)#'; обратите внимание, что это соответствует файлам как в текущем каталоге, так и в подкаталогах.
[*]pathlib: ** что означает «этот каталог и все подкаталоги рекурсивно»
[*]python glob: если рекурсивно установлено значение true, шаблон ** будет соответствовать любым файлам и нулю или более каталогов, подкаталогов и символических ссылок на каталоги. Если за шаблоном следует os.sep или os.altsep, файлы не будут совпадать.
[*]ruby: ** Сопоставляет каталоги рекурсивно, если за ними следует /. Если этот сегмент пути содержит какие-либо другие символы, он аналогичен обычному *.
[/list] [b]Вопросы: [/b] [list] [*]Правильны ли мои предположения о том, что должен делать каждый шарик?
[*]Почему Bash — единственный рекурсивный инструмент с **? (если вы добавите setopt GLOBSTARSHORT в zsh, результат будет аналогичен **
[*]Is разумно сказать себе, что **/* работает для всех