Как создать несколько файлов tar.gz, переопределив определенные файлы для каждой среды?

Прочитать всю справочную страницу:

  CPU
       These are percentages of total CPU time.
       us: Time spent running non-kernel code.  (user time, including nice time)
       sy: Time spent running kernel code.  (system time)
       id: Time spent idle.  Prior to Linux 2.5.41, this includes IO-wait time.
       wa: Time spent waiting for IO.  Prior to Linux 2.5.41, included in idle.
       st: Time stolen from a virtual machine.  Prior to Linux 2.6.11, unknown.

Все это проценты от общего времени процессора.

2
15.08.2020, 14:07
3 ответа

Способов может быть множество, хотя все они требуют некоторой сложности для обработки случая переопределения.

В качестве одного -вкладыша, хотя и немного длинного, вы могли бы сделать это для одной итерации, т.е. для одного каталога "environments":

(r=Products; e=stage; (find -- "$r" -regextype posix-extended -maxdepth 2 \( -regex '^[^/]+(/[^/]+)?' -o ! -type d \) -print0; find -- "$r" -mindepth 1 -path "$r/*/$e/*" -print0) | tar --null --no-recursion -czf "$r-$e.tgz" -T- --transform=s'%^\(\([^/]\{1,\}/\)\{2\}\)[^/]\{1,\}/%\1%')

разбито для лучшего наблюдения:

(
    r=Products; e=stage
    (
        find -- "$r" -regextype posix-extended -maxdepth 2 \( -regex '^[^/]+(/[^/]+)?' -o ! -type d \) -print0
        find -- "$r" -mindepth 1 -path "$r/*/$e/*" -print0
    ) \
        | tar --null --no-recursion -czf "$r-$e.tgz" -T- \
            --transform=s'%^\(\([^/]\{1,\}/\)\{2\}\)[^/]\{1,\}/%\1%'
)

На что следует обратить внимание:

  1. показывает синтаксис инструментов GNU.Для BSD findвы должны заменить -regextype posix-extendedтолько на -E, а для BSD tarвы должны заменить --no-recursionтолько на -n, а также--transform=s(< -обратите внимание на окончательныйs)на просто-s
  2. для простоты демонстрации предполагается, что фрагмент запускается из каталога, содержащего Products, и использует пользовательскую переменную $eдля имени каталога «environments» для архивирования, а $r— это просто короткий -именованная вспомогательная переменная, содержащая имя Products
  3. он заключен в круглые скобки, что делает его подоболочкой, просто чтобы не загрязнять вашу оболочку $rи $e, если вы запускаете ее из команды -строка
  4. он не копирует исходные файлы и не ссылается на них, он обрабатывает любые допустимые имена файлов, не имеет ограничений по памяти и может обрабатывать любое количество имен; единственное предположение касается первых двух уровней иерархии каталогов в том, что любой каталог непосредственно ниже первого уровня считается каталогом «окружения» и, таким образом, игнорируется (, за исключением того, который указан в$e)

Вы можете просто заключить этот фрагмент в цикл оболочки for e in dev prod stage; do...; doneи просто работать. (, возможно, удаляя крайние круглые скобки и окружая весь цикл for).

Положительным моментом является то, что он довольно короткий и относительно простой.

Недостатком является то, что он всегда архивирует также все переопределенные файлы (, т.е. базовые ), хитрость в том, что двойные findкоманды подают tarс to -должны быть -переопределенными файлами в первую очередь, и, следовательно, во время извлечения они будут перезаписаны переопределяющими файлами (, т.е. файлами, специфичными для "окружения" ). Это приводит к тому, что больший архив занимает больше времени как при создании, так и при извлечении, и может быть нежелательным в зависимости от того, можно ли такими «накладными расходами» пренебречь или нет.

Этот конвейер, описанный в прозе,:

  1. (кроме крайних скобок и вспомогательных переменных)
  2. первая команда findсоздает список не -конкретных файлов (и ведущих каталогов только в соответствии с вашим обновлением ), а вторая findсоздает список всех сред, -специфичных только файлы
  3. две команды findсами по себе заключены в круглые скобки, так что оба их выхода подают канал в tarпоследовательно
  4. tarсчитывает такой канал, чтобы получить имена файлов, и помещает эти файлы в архив, а также--transform-считывает их имена, удаляя компонент «среды» (, если он присутствует )из пути -имя каждого файла
  5. две findкоманды разделены вместо одной, и они выполняются одна за другой, так что не -определенные файлы создаются (для tarиспользования )до специфические файлы среды -, что позволяет использовать трюк, описанный ранее

Чтобы избежать накладных расходов, связанных с включением всегда всех файлов, нам нужны дополнительные сложности, чтобы действительно очистить переопределенные файлы. Один из способов может быть таким, как показано ниже:

# still a pipeline, but this time I won't even pretend it to be a one-liner

(
r=Products; e=stage; LC_ALL=C
find -- "$r" -regextype posix-extended \( -path "$r/*/$e/*" -o \( -regex '^([^/]+/){2}[^/]+' ! -type d \) -o -regex '^[^/]+(/[^/]+)?' \) -print0 \
    | sed -zE '\%^(([^/]+/){2})([^/]+/)%s%%0/\3\1%;t;s%^%1//%' \
    | sort -zt/ -k 3 -k 1,1n \
    | sort -zut/ -k 3 \
    | sed -zE 's%^[01]/(([^/]+/)|/)(([^/]+/?){2})%\3\2%' \
    | tar --null --no-recursion -czf "$r-$e.tgz" -T- \
        --transform=s'%^\(\([^/]\{1,\}/\)\{2\}\)[^/]\{1,\}/%\1%'
)

Несколько замечаний:

  1. все, что мы говорили ранее о синтаксисе GNU и BSD для findи tar, применимо и здесь
  2. как и предыдущее решение, оно не имеет никаких ограничений, кроме предположения о первых двух уровнях иерархии каталогов
  3. Здесь я использую GNU sedдля работы с нулевым -вводом-выводом с разделителями (параметром -z), но вы можете легко заменить эти две sedкоманды, например, на. потребуется while read...цикл оболочки (Bash версии 3 или выше )или другой язык, в котором вы чувствуете себя уверенно,единственная рекомендация заключается в том, что инструмент, который вы используете, может обрабатывать ввод-вывод с нулевыми -разделителями (, например. GNU gawkможет это сделать ); см. ниже замену с использованием циклов Bash
  4. Я использую здесь один единственный find, так как я не полагаюсь на какое-либо подразумеваемое поведение изtar
  5. Команды sedуправляют списком имен, прокладывая путь для команд sort
  6. в частности, первый sedперемещает имя «окружения» в начало пути, также добавляя к нему префикс вспомогательного номера 0, просто чтобы он сортировался перед файлами не -окружения, как я' m, добавляя к ним префикс 1для сортировки
  7. такая подготовка нормализует список имен в «глазах» команд sort, делая все имена без имени «окружения» и все имеющие одинаковое количество полей, разделенных косой чертой -в начале, что важно для определения ключей sort
  8. первый sortприменяет сортировку, основанную сначала на именах файлов, таким образом располагая одинаковые имена рядом друг с другом, а затем по числовому значению 0или 1, как отмечено ранее командой sed, тем самым гарантируя, что любой файл, относящийся к "окружениям", если он присутствует, предшествует его неспецифичному -аналогу
  9. второй sortобъединяет (параметр-u)в именах файлов, оставляя только первое из повторяющихся имен, которое из-за предыдущего переупорядочения всегда является файлом, специфичным для "окружения", если оно присутствует
  10. наконец, второй sedотменяет то, что было сделано первым, тем самым изменяя имена файлов для tarна архивные

Если вам интересно изучить промежуточные части такого длинного конвейера, имейте в виду, что все они работают с нулевыми-именами с разделителями и, следовательно, плохо отображаются на экране. Вы можете подключить любой из промежуточных выходов (, т.е.убрав по крайней мереtar)на любезность tr '\0' '\n', чтобы показать человекоподобный -вывод, просто помните, что имена файлов с новыми строками будут занимать две строки на экране.

Можно было бы сделать несколько улучшений, конечно же, сделав его полностью параметризованной функцией/скриптом или, например, автоматически обнаружив любое произвольное имя для каталогов «окружения», как показано ниже:

Внимание!:Обратите внимание на комментарии, так как интерактивная оболочка может их не принять.

(
export r=Products LC_ALL=C
cd -- "$r/.." || exit
# make arguments out of all directories lying at the second level of the hierarchy
set -- "$r"/*/*/
# then expand all such paths found, take their basenames only, uniquify them, and pass them along xargs down to a Bash pipeline the same as above
printf %s\\0 "${@#*/*/}" \
    | sort -zu \
    | xargs -0I{} sh -c '
e="${1%/}"
echo --- "$e" ---
find -- "$r" -regextype posix-extended \( -path "$r/*/$e/*" -o \( -regex '\''^([^/]+/){2}[^/]+'\'' ! -type d \) -o -regex '\''^[^/]+(/[^/]+)?'\'' \) -print0 \
    | sed -zE '\''\%^(([^/]+/){2})([^/]+/)%s%%0/\3\1%;t;s%^%1//%'\'' \
    | sort -zt/ -k 3 -k 1,1n \
    | sort -zut/ -k 3 \
    | sed -zE '\''s%^[01]/(([^/]+/)|/)(([^/]+/?){2})%\3\2%'\'' \
    | tar --null --no-recursion -czf "$r-$e.tgz" -T- \
        --transform=s'\''%^\(\([^/]\{1,\}/\)\{2\}\)[^/]\{1,\}/%\1%'\''
' packetizer {}
)

Пример замены первой команды sedциклом Bash:

(IFS=/; while read -ra parts -d $'\0'; do
    if [ "${#parts[@]}" -gt 3 ]; then
        env="${parts[2]}"; unset parts[2]
        printf 0/%s/%s\\0 "$env" "${parts[*]}"
    else
        printf 1//%s\\0 "${parts[*]}"
    fi
done)

Для второй sedкоманды:

(IFS=/; while read -ra parts -d $'\0'; do
    printf %s "${parts[*]:2:2}" "/${parts[1]:+${parts[1]}/}" "${parts[*]:4}"
    printf \\0
done)

Для обоих фрагментов требуются окружающие круглые скобки, чтобы их можно было -заменить соответствующими командами sedв приведенном выше конвейере, и, конечно же, часть sh -cпосле xargsнеобходимо превратить в bash -c. ].

1
18.03.2021, 23:13

Общее решение

  1. Сделайте копию дерева каталогов. Жесткие ссылки на файлы для экономии места.
  2. Измените копию. (В случае жестких ссылок вам нужно знать, что можно сделать безопасно. Смотри ниже.)
  3. Архивировать копию.
  4. Удалите копию.
  5. При необходимости повторите (, изменив )по-другому.

Пример

Ограничения:

  • в этом примере используются не -опции POSIX (, протестированные в Debian 10 ),
  • он делает некоторые предположения о дереве каталогов,
  • может произойти сбой, если файлов слишком много.

Рассматривайте это как доказательство концепции, настройте его под свои нужды.

  1. Создание копии

    cdв родительский каталог Products. Этот каталог Productsи все, что внутри, должно принадлежать одной файловой системе. Создайте временный каталог и воссоздайте Productsтам:

    mkdir -p tmp
    cp -la Products/ tmp/
    
  2. Изменение копии

    Файлы в двух деревьях каталогов жестко связаны. Если вы измените их содержимое , вы измените исходные данные. Операции, которые изменяют информацию, хранящуюся в каталогах, безопасны, они не изменят исходные данные, если они выполняются в другом дереве. Это:

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

    В вашем случае для каждого каталога с именем devна нужной глубине переместите его содержимое на один уровень вверх:

    cd tmp/Products
    dname=dev
    find. -mindepth 2 -maxdepth 2 -type d -name "$dname" -exec sh -c 'cd "$1" && mv -f -- *../' sh {} \;
    

    Примечания:

    • mv -- *../склонен к argument list too long,
    • по умолчанию *не соответствует точечным файлам.

    Затем удалите каталоги:

    find. -mindepth 2 -maxdepth 2 -type d -exec rm -rf {} +
    

    Обратите внимание, что это удаляет теперь пустые devи ненужные prod, stage; и любой другой каталог на этой глубине.

  3. Архивирование копии

    # still in tmp/Products because of the previous step
    cd..
    tar cvzf "products-$dname.tgz" Products
    
  4. Удаление копии

    # now in tmp because of the previous step
    rm -rf Products
    
  5. Повтор

    Вернитесь в нужный каталог и начните заново, на этот раз с помощью dname=stage; и так далее.


Пример скрипта (быстрый и грязный)

#!/bin/bash

dir=Products
[ -d "$dir" ] || exit 1
mkdir -p tmp

for dname in dev prod stage; do
(
   cp -la "$dir" tmp/
   cd "tmp/$dir"
   [ "$?" -eq 0 ] || exit 1
   find. -mindepth 2 -maxdepth 2 -type d -name "$dname" -exec sh -c 'cd "$1" && mv -f -- *../' sh {} \;
   find. -mindepth 2 -maxdepth 2 -type d -exec rm -rf {} +
   cd..
   [ "$?" -eq 0 ] || exit 1
   tar cvzf "${dir,,}-$dname.tgz" "$dir"
   rm -rf "$dir" || exit 1
) || exit "$?"
done
1
18.03.2021, 23:13

Я сделал это немного более общим и работал с нетривиальными -именами файлов без фактического изменения исходных каталогов

Productsприводится в качестве аргумента. ключевые слова dev prod stageжестко -закодированы внутри скрипта (, но могут быть легко изменены)

Примечание :это специальное расширение GNU --transformи-print0-z

запустить скрипт
./script Products

#!/bin/sh

# environment
subdirs="dev prod stage"

# script requires arguments
[ -n "$1" ] || exit 1

# remove trailing /
while [ ${i:-0} -le $# ]
  do
    i=$((i+1))
    dir="$1"
    while [ "${dir#"${dir%?}"}" = "/" ]
      do
        dir="${dir%/}"
    done
    set -- "$@" "$dir"
    shift
done

# search string
for sub in $subdirs
  do
    [ -n "$search" ] && search="$search -o -name $sub" || search="( -name $sub"
done
search="$search )"

# GNU specific zero terminated handling for non-trivial directory names
excludes="$excludes $(find -L "$@" -type d $search -print0 | sed -z 's,[^/]*/,*/,g' | sort -z | uniq -z | xargs -0 printf '--exclude=%s\n')"

# for each argument
for dir in "$@"
  do
    # for each environment
    [ -e "$dir" ] || continue
    for sub in $subdirs
      do
        # exclude other subdirs
        exclude=$(echo "$excludes" | grep -v "$sub")

#        # exclude files that exist in subdir (at least stable against newlines and spaces in file names)
#        include=$(echo "$excludes" | grep "$sub" | cut -d= -f2)
#        [ -n "$include" ] && files=$(find $include -mindepth 1 -maxdepth 1 -print0 | tr '\n[[:space:]]' '?' | sed -z "s,/$sub/,/," | xargs -0 printf '--exclude=%s\n')
#        exclude="$exclude $files"

        # create tarball archive
        archive="${dir##*/}-${sub}.tgz"
        [ -f "$archive" ] && echo "WARNING: '$archive' is overwritten"
        tar --transform "s,/$sub$,," --transform "s,/$sub/,/," $exclude -czhf "$archive" "$dir"
    done
done

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

Тем не менее, это требует дополнительной проверки согласованного поведения (не уверен в этом ). правильнее было бы исключить files1.json+ files5.jsonк сожалению -Xне работает с--null

Если вы не доверяете такому поведению или не хотите дублировать файлы в архивах, вы можете добавить исключение для простых имен файлов. раскомментируйте код выше tar. символы новой строки и пробелы разрешены в именах файлов, но будут исключены с помощью подстановочного знака ?в шаблоне исключения, который теоретически может исключить больше файлов, чем ожидалось (, если есть похожие файлы, соответствующие этому шаблону)

вы можете поместить echoперед tar, и вы увидите, что скрипт генерирует следующие команды

tar --transform 's,/dev$,,' --transform 's,/dev/,/,' --exclude=*/*/prod --exclude=*/*/stage -czhf Products-dev.tgz Products
tar --transform 's,/prod$,,' --transform 's,/prod/,/,' --exclude=*/*/dev --exclude=*/*/stage -czhf Products-prod.tgz Products
tar --transform 's,/stage$,,' --transform 's,/stage/,/,' --exclude=*/*/dev --exclude=*/*/prod -czhf Products-stage.tgz Products
0
18.03.2021, 23:13

Теги

Похожие вопросы