ИспользованиеXMLStarlet
:
xml sel -t -v '//binariesDir' filestore.xml
в Ubuntu с установленным пакетом xmlstarlet
, мне нужно использовать этот:
xmlstarlet sel -t -v '//binariesDir' filestore.xml
Следующее найдет все обычные файлы в или ниже ./to_keep
и вызовет скрипт в -строке sh -c
с их пакетами. Для каждой партии путей скрипт в строке -будет вызывать find
один раз, чтобы найти обычные файлы в ./to_purge
с такими же именами. Пути этих файлов в ./to_purge
будут напечатаны (, чтобы удалить их, добавьте -delete
после-print
).
find to_keep -type f -exec sh -c '
for pathname do
set -- "$@" -o -name "${pathname##*/}"
shift
done; shift
find to_purge \( "$@" \) -type f -print' sh {} +
или, по запросу, в одну строку:
find to_keep -type f -exec sh -c 'for pathname do set -- "$@" -o -name "${pathname##*/}"; shift; done; shift; find to_purge \( "$@" \) -type f -print' sh {} +
Сценарий строки -строит список операций ИЛИ -из -name
тестов для команды find
, которую он использует в своей последней строке. Цикл создает этот список в позиционных параметрах из компонента имени файла каждого пути, который ему передал внешний find
.
Это относится ко всем разрешенным именам файлов, включая имена файлов, содержащие пробелы, символы табуляции и символы новой строки. Опять же, чтобы удалить файлы, добавьте-delete
(или-exec rm {} +
)после -print
в коде.
В виде короткого сценария, который принимает «сохранить каталог» и «очистить каталог» в качестве аргументов командной строки:
#!/bin/sh
keepdir=$1
purgedir=$2
find "$keepdir" -type f -exec sh -c '
dir=$1; shift
for pathname do
set -- "$@" -o -name "${pathname##*/}"
shift
done; shift
find "$dir" \( "$@" \) -type f -print' sh "$purgedir" {} +
Единственная проблема с этим кодом заключается в том, что он будет использовать имена в одном каталоге в качестве шаблонов для поиска имен файлов в другом каталоге. Это означает, что если файл в первом каталоге называется *
, все файлы во втором каталоге удаляются.Вы можете исправить это, защитив имена файлов во внутреннемfind
:
for pathname do
sane=$( printf "%s\n" "${pathname##*/}" | sed "s/[[*?]/\\&/g" )
set -- "$@" -o -name "$sane"
shift
done; shift
Эта модификация цикла в сценарии -строки sh -c
экранирует символы [
, *
и ?
(, которые в противном случае использовались в качестве шаблонов подстановки имен файлов ). Сценарий теперь не будет работать с именами файлов, которые заканчиваются новой строкой (из-за используемой подстановки команд ), но, возможно, с этим можно жить.
Типично, не успел написать, как нашел ответ!
find./to_keep/ -type f -exec basename '{}' \; | xargs --max-args=1 find./to_purge/ -name | xargs --max-args=1 rm
Я не приму это как ответ, так как я еще не знаю, что не так с моими предыдущими попытками.