Рекурсивное сопоставление имен файлов с аргументом glob - PullRequest
4 голосов
/ 24 мая 2011

Я пытался получить список файлов, соответствующих шаблону glob в аргументе командной строки (sys.argv[1]), рекурсивно используя glob.glob и os.walk. Проблема в том, что bash (и, похоже, многие другие оболочки) автоматически расширяет шаблоны glob в имена файлов.

Как стандартные программы Unix (например, grep -R) делают это тогда? Я понимаю, что они не в Python, но если это происходит на уровне оболочки, это не должно иметь значения, верно? Есть ли способ для сценария сказать оболочке, что не нужно автоматически расширять шаблоны глобуса? Похоже, set -f отключит глобализацию, но я не уверен, как запустить это достаточно рано, так сказать.

Я видел Использовать Glob () для рекурсивного поиска файлов в Python? , но это не касается фактического получения шаблонов glob из аргументов командной строки.

Спасибо!

Edit:

grep-подобный perl-скрипт ack принимает регулярное выражение perl в качестве одного из аргументов. Таким образом, ack .* печатает каждую строку каждого файла. Но .* должен распространяться на все скрытые файлы в каталоге. Я пытался прочитать сценарий, но я не знаю Perl; как это можно сделать?

Ответы [ 3 ]

6 голосов
/ 24 мая 2011

Оболочка выполняет расширение glob, прежде чем она даже подумает о вызове команды. Такие программы, как grep, ничего не делают, чтобы предотвратить тряску: они не могут. Вы, как вызывающая сторона этих программ, должны сказать оболочке, что вы хотите передать программе специальные символы, такие как * и ?, и не позволять оболочке интерпретировать их. Вы делаете это, помещая их в кавычки:

grep -E 'ba(na)* split' *.txt

(ищите ba split, bana split и т. Д. Во всех файлах с именем .txt). В этом случае одинарные или двойные кавычки будут работать. Между одинарными кавычками оболочка ничего не расширяет. Между двойными кавычками по-прежнему интерпретируются $, ` и \. Вы также можете защитить один символ от расширения оболочки, поставив перед ним обратную косую черту. Это не только символы подстановки, которые должны быть защищены; например, выше, пробел в шаблоне указан в кавычках, поэтому он является частью аргумента grep, а не разделителем аргументов. Альтернативные способы написания приведенного выше фрагмента включают

grep -E "ba(na)* split" *.txt
grep -E ba\(na\)\*\ split *.txt

В большинстве оболочек, если аргумент содержит символы подстановки, но шаблон не соответствует ни одному файлу, шаблон остается неизменным и передается базовой команде. Так что команда вроде

grep b[an]*a *.txt

имеет различный эффект в зависимости от того, какие файлы присутствуют в системе. Если в текущем каталоге нет файлов, имя которых начинается с b, команда ищет шаблон b[an]*a в файлах, имя которых соответствует *.txt. Если текущий каталог содержит файлы с именами baclava, bnm и hello.txt, команда расширяется до grep baclava bnm hello.txt, поэтому она ищет шаблон baclava в двух файлах bnm и hello.txt. Само собой разумеется, это плохая идея полагаться на это в сценариях; в командной строке иногда можно сохранить набор текста, но это рискованно.

Когда вы запускаете ack .* в каталоге, в котором нет файла точек, оболочка запускает ack . ... Поведение команды ack заключается в печати всех непустых строк (шаблон .: соответствует любому одному символу) во всех файлах под .. (родительский элемент текущего каталога) рекурсивно. Сравните с ack '.*', который ищет шаблон .* (который совпадает с любым) в текущем каталоге и его подкаталогах (из-за поведения ack, когда вы не передаете аргумент имени файла).

1 голос
/ 24 мая 2011

Да, set -f, вы на правильном пути.

Похоже, вы собираетесь вызывать свою программу на Python из оболочки.

Каждый раз, когда вы используете оболочку для выдачи команды, она пытается сканировать строку cmd и обрабатывает подстановочные знаки, подстановку команд и целый ряд других вещей.

Поэтому перед запуском программы в командной строке необходимо отключить глобирование

set -f
echo *
*

myprogram *.txt

передаст строку '* .txt' вашей программе. Затем вы можете использовать внутреннюю глобализацию, чтобы получить ваши файлы.

ИЛИ, по сути, вы можете сделать то же самое, создав скрипт-обертку

 #!/bin/bash
 set -f
 myProgram ${@}

где ${@} are the arguments you pass in when you start myProgram` из командной строки, crontab или через exec (...) из другого процесса.

Надеюсь, это поможет.

1 голос
/ 24 мая 2011

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

...