Поиск каталогов с помощью команды find в bash с использованием списка исключений - PullRequest
6 голосов
/ 15 ноября 2011

сейчас, прежде чем вы думаете, «это было сделано раньше», пожалуйста, продолжайте

Как и большинство людей, пытающихся сделать скрипт find 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, / test, / html, / icons Это доказывает, что концепцияработает, но теперь, чтобы продвинуться немного дальше, мне нужно использовать find, чтобы искать 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, а не некоторую для цикла.Любой конструктивный вклад будет оценен.

Ответы [ 3 ]

5 голосов
/ 15 ноября 2011

Попробуйте что-то вроде

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

и посмотрим, что получится.

РЕДАКТИРОВАТЬ: добавлен ведущий * к каждому пути, как в вашем примере.

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

#!/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, исключая перечисленные в $ ignore, при условии, что в $ ignore по крайней мере два (исправление несложно).

2 голосов
/ 28 февраля 2015

Существующие ответы содержат ошибки, если заданы имена каталогов, которые содержат буквенные пробелы.Безопасной и надежной практикой является использование петли.Если ваша задача использовать «мощь 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 голосов
/ 16 ноября 2011
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 вокруг всего этого.Известной проблемой может быть каталог, содержащий пробел в имени.Это, однако, было решено, поэтому, стараясь сделать его простым, я думаю, что это отвечает на мой вопрос.

...