2011-11-15 4 views
5

сейчас, прежде чем вы думаете, «это было сделано раньше», пожалуйста, прочитайте.Поиск каталогов с поиском в bash с использованием списка исключений

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

Я пишу небольшую резервную программу прямо сейчас, чтобы делать резервные копии каталогов и вам нужно их найти, против списка директив, который должен быть исключен. Легче сказать, чем сделать. Позвольте мне задать этап:

#!/bin/bash 
BasePath="/home/adesso/baldar" 
declare -a Iggy 
Iggy=("/cgi-bin" 
    "/tmp" 
    "/test" 
    "/html" 
    "/icons") 
IggySubdomains=$(printf ",%s" "${Iggy[@]}") 
IggySubdomains=${IggySubdomains:1} 
echo $IggySubdomains 
exit 0 

Теперь в конце этого вы получите /CGI-BIN,/TMP,/тест,/HTML,/значки Это доказывает, что концепция работает, но теперь принять его немного дальше, мне нужно использовать поиск искать BasePath и поиск только один уровень для всех подкаталогов и исключить список подкаталогов в массиве ...

Если я печатаю это вручную было бы :

find /var/www/* \(-path '*/cgi-bin' -o -path '*/tmp' -o -path '*/test' -o -path '*/html' -o -path '*/icons' \) -prune -type d 

И, может быть, мне захочется зациклиться на каждом подкаталоге и сделать то же самое ... Надеюсь, вы поняли мою мысль.

Итак, что я пытаюсь сделать, кажется возможным, но у меня есть небольшая проблема, printf ",% s" мне не нравится, используя все эти параметры find -path или -o. Означает ли это, что я должен снова использовать eval?

Я пытаюсь использовать силу bash здесь, а не некоторый цикл. Любой конструктивный вклад будет оценен.

+0

Вам не нужно 'declare -a', присваивания достаточно. Имена переменных в bash обычно строчные (или все шапки для переменных среды), а не верблюд.Нет необходимости «выходить 0» в конце ('echo' вернет 0 anayway). – Sorpigal

+1

CamelCase просто делает материал легким для чтения и привычным для меня я вроде как, я предполагаю, что он ничего не сломает ... но спасибо за другие советы, я действительно начинаю любить сообщество здесь. : D –

+0

Yup, CamelCase в порядке; единственное место, где неправильные имена переменных приводят к ошибкам, - это использование ALL_CAPS для вещей, которые не являются переменными среды или встроенными (поскольку это приводит к конфликтам с переменными, которые _are_ в одном из этих классов). –

ответ

5

Try что-то вроде

find /var/www/* \(-path "${Iggy[0]}" $(printf -- '-o -path "*%s" ' "${Iggy[@]:1}") \) -prune -type d 

и посмотреть, что происходит.

EDIT: добавлен ведущий * к каждому пути, как в вашем примере.

И вот полное решение, основанное на вашем описании.

#!/usr/bin/env bash 
basepath="/home/adesso/baldar" 
ignore=("/cgi-bin" "/tmp" "/test" "/html" "/icons") 

find "${basepath}" -maxdepth 1 -not \(-path "*${ignore[0]}" $(printf -- '-o -path "*%s" ' "${ignore[@]:1}") \) -not -path "${basepath}" -type d 

Поддиректории $ BasePath за исключением тех, которые перечислены в $ игнорировать, полагая, по крайней мере, два в $ игнорировать (крепление, которое не трудно).

+0

Итак, я закончил перенос кода в подстановке команд и назначил его переменной, но хотел бы, чтобы это был массив, поэтому я могу закодировать значения и сделать свою резервную копию для каждого каталога. 'SubDomains = $ (find $ {BasePath}/* -maxdepth 0 -not \ (-path" * $ {Iggy [0]} "$ (printf - '-o -path" *% s "'" $ { Iggy [@]: 1} ") \) -тип d)' Я не могу найти смысла - вы используете в printf ?? Извините за CamelCase –

+0

Попробуйте 'printf '-o'' самостоятельно, и вы увидите, что он делает. Чтобы преобразовать результаты этого поиска в массив, я рекомендую небольшую подстановку команд и чтение, например. 'while IFS = read -r file; do ... done <<(find ...) ' – Sorpigal

+0

Это очень похоже на то, что это столкнулось бы с проблемой, если список' ignore' содержит строки с литеральными кавычками, пробелами и т. д. Гораздо безопаснее создавать строки в одиночный кавычек, вместо того, чтобы использовать подстановку команд для генерации строки, которая затем разделяется по строкам и расширяется. –

0
FIND="$(which find --skip-alias)" 
BasePath="/home/adesso/baldar" 
Iggy=("/cgi-bin" 
    "/tmp" 
    "/test" 
    "/html" 
    "/icons") 
SubDomains=($(${FIND} ${BasePath}/* -maxdepth 0 -not \(-path "*${Iggy[0]}" $(printf -- '-o -path "*%s" ' "${Iggy[@]:1}") \) -type d)) 
echo ${SubDomains[1]} 

Благодаря @Sorpigal У меня есть решение. Я в конечном итоге вложил подстановку команд, поэтому я могу использовать скрипт в cron и, наконец, добавить определение Array во всем этом. Известной проблемой будет каталог, содержащий пробел в имени. Это, однако, было решено, поэтому, пытаясь сохранить его просто, я думаю, что это отвечает на мой вопрос.

2

Существующие ответы ошибочны, если заданы имена каталогов, которые содержат буквальные пробелы. Безопасная и надежная практика заключается в использовании цикла. Если ваша проблема связана с «мощью bash», я бы сказал, что надежное решение более мощное, чем багги. :)

BasePath="/home/adesso/baldar" 
declare -a Iggy=("/cgi-bin" "/tmp" "/test" "/html" "/icons") 

find_cmd=(find "$BasePath" '(') 

## This is the conventional approach: 
# for x in "${Iggy[@]}"; do 
# find_cmd+=(-path "*${x}" -o) 
#done 

## This is the unconventional, only-barely-safe approach 
## ...used only to avoid looping: 
printf -v find_cmd_str ' -path "*"%q -o ' "${Iggy[@]}" 
find_cmd_str=${find_cmd_str%" -o "} 
eval "find_cmd+=($find_cmd_str)" 

find_cmd=("${find_cmd[@]:0:${#find_cmd[@]} - 1}" 

# and add the suffix 
find_cmd+=(')' -prune -type d) 

# ...finally, to run the command: 
"${find_cmd[@]}" 
+0

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

+0

Во многих подобных случаях умное использование операторов расширения параметров будет делать трюк (например, добавление или суффикс каждого элемента массива). Не уверен, что любой из этих трюков применим здесь небрежно. И да, я понимаю то, о чем вы просили, - но имеет несколько сильную висцеральную реакцию на любой вопрос, где «правильный» ответ - это код, который никто никогда не должен использовать в производственной системе. Если вы нашли ** безопасный ** нециклический ответ, он, безусловно, получил бы мой голос. –

+0

@ WillemP.Botha, ... Я действительно исправил это, чтобы избежать цикла; хотя это ужасный ужасный взлом, 'printf '% q'' _does_ делает этот eval-safe. –

Смежные вопросы