Найдите название подкаталогов и файлы процесса в каждом
Скажем /tmp
имеет подкаталоги /test1
, /test2
, /test3
и так далее, и у каждого есть несколько файлов внутри.
Я должен запустить while
петля или for
цикл, чтобы найти имя каталогов (в этом случае /test1
, /test2
,...) и запустите команду, которая обрабатывает все файлы внутри каждого каталога.
Так, например, я должен получить имена каталогов в /tmp
которые будут test1
, test2
... Для каждого подкаталога мне нужно обработать файлы внутри него.
Как я могу это сделать?
Разъяснение:
Это команда, которую я хочу выполнить:
find /PROD/140725_D0/ -name "*.json" -exec /tmp/test.py {} \;
где 140725_D0
пример одного подкаталога для обработки - есть несколько магазинов с разными именами.
Итак, используя for
или же while
цикл, я хочу найти все подкаталоги и запустить команду для файлов в каждом.
for
или же while
цикл должен итеративно заменять жестко закодированное имя 140725_D0
в команде поиска выше.
5 ответов
Вы должны быть в состоянии сделать с одним find
команда со встроенной командой оболочки:
find /PROD -type d -execdir sh -c 'for f in *.json; do /tmp/test.py "$f"; done' \;
Замечания: -execdir
не совместим с POSIX, но версии BSD (OSX) и GNU (Linux) find
поддержать это; ниже смотрите альтернативу POSIX.
- Подход состоит в том, чтобы
find
сопоставить каталоги, а затем в каждом сопоставленном каталоге выполнить оболочку с циклом обработки файлов (sh -c '<shellCmd>'
). - Если не все подкаталоги гарантированно имеют
*.json
файлы, измените команду оболочки наfor f in *.json; do [ -f "$f" ] && /tmp/test.py "$f"; done
Обновление: еще два соображения; Кончик шляпы к ответу Кенорба:
По умолчанию,
find
обрабатывает все поддерево входного каталога. Чтобы ограничить соответствие непосредственными подкаталогами, используйте-maxdepth 1
[1]:find /PROD -maxdepth 1 -type d ...
Как указано,
-execdir
- который запускает команду, переданную ему в каталоге, обрабатываемом в данный момент - не совместим с POSIX; Вы можете обойти это, используя-exec
вместо этого и путем включенияcd
команда с указанием пути к каталогу ({}
) в команде оболочки:find /PROD -type d -exec sh -c 'cd "{}" && for f in *.json; do /tmp/test.py "$f"; done' \;
[1] Строго говоря, вы можете разместить -maxdepth
вариант в любом месте после пути входного файла на find
командная строка - как опция, она не позиционная. Тем не менее, GNU find
выдаст предупреждение, если вы не разместите его перед тестами (например, -type
) и действия (такие как -exec
).
Попробуйте следующее использование find
:
find . -type d -exec sh -c 'cd "{}" && echo Do some stuff for {}, files are: $(ls *.*)' ';'
использование -maxdepth
если вы хотите ограничить уровни каталогов.
Другое решение - немного изменить код Python внутри вашего скрипта, чтобы принимать и обрабатывать несколько файлов. Например, если ваш скрипт содержит что-то вроде:
def process(fname):
print 'Processing file', fname
if __name__ == '__main__':
import sys
process(sys.argv[1])
Вы можете заменить последнюю строку на:
for fname in sys.argv[1:]:
process(fname)
После этой простой модификации вы можете назвать свой скрипт следующим образом:
/tmp/test.py /PROD/*/*.json
и пусть он обрабатывает все нужные файлы JSON.
Вы можете сделать это, используя функцию подоболочки bash:
for i in /tmp/test*; do
# don't do anything if there's no /test directory in /tmp
[ "$i" != "/tmp/test*" ] || continue
for j in $i/*.json; do
# don't do anything if there's nothing to run
[ "$j" != "$i/*.json" ] || continue
(cd $i && ./file_to_run)
done
done
Когда вы заключаете команду в (
а также )
он запускает подоболочку для запуска команды. Подоболочка похожа на запуск другого экземпляра bash, за исключением того, что она немного более оптимальна.
Вы также можете просто попросить оболочку развернуть нужные вам каталоги / файлы, например, используя команду xargs
:
echo /PROD/*/*.json | xargs -n 1 /tmp/test.py
или даже используя свой оригинал find
команда:
find /PROD/* -name "*.json" -exec /tmp/test.py {} \;
Обе команды будут обрабатывать все файлы JSON, содержащиеся в любом подкаталоге /PROD
,