Как заархивировать список каталогов, только если они существуют

Я сам отвечу на свой вопрос, так как сам читал исходный код и занимался исследовательской работой. Если бы я сам не провел некоторую исследовательскую работу, мне очень помогли бы ответы Frostschutz и Sourcejedi — они кажутся правильными, насколько я знаю (, хотя и не так подробно, но они дают вам отправной точкой, чтобы провести остальную часть исследования самостоятельно ).

Немного теории :Существует два вида дисциплин организации очередей :классовые и бесклассовые.

Классовые дисциплины (как говорится в ответе sourcejedi )гибкие. Они позволяют вам присоединять к ним дочерние классовые qdisc и могут совместно использовать полосу пропускания с другими классами, когда это возможно.Листовые классы имеют бесклассовый qdisc (elementary/fundamental qdisc ), прикрепленный к ним (, также называемый элементарным qdisc ). Очереди, управляемые этими элементарными qdisc, — это место, где пакеты помещаются в очередь и удаляются из очереди. Пакеты удаляются из очереди и помещаются в очередь из этих классов с помощью алгоритма, соответствующего классу. Примерами классовых qdisc являются :HTB и CBQ.

Бесклассовые qdisc — это фундаментальные или элементарные qdisc, которые являются жесткими в том смысле, что к ним не могут быть прикреплены дочерние qdisc, а также они не могут совместно использовать полосу пропускания. Говоря наивным языком, они предоставлены сами себе. Эти qdisc владеют очередью, из которой они ставят в очередь и удаляют пакеты в соответствии с алгоритмом, соответствующим qdisc. Примеры бесклассового qdisc :pfifo, bfifo, pfifo _fast (по умолчанию, используемые в Linux tc ), tbf, sfq и некоторые другие.

В примере дерева в вопросе каждый из листовых классов htb 1 :1, 1 :2 и 1 :3 имеет прикрепленный к нему элементарный qdisc, который по умолчанию является pfifo (не pfifo _быстро ). Элементарный qdisc, прикрепленный к листу, можно изменить с помощью пользовательской утилиты tcследующим образом:

tc qdisc add dev eth0 parent 1:11 handle 30: pfifo limit 5 
tc qdisc add dev eth0 parent 1:12 handle 40: sfq perturb 10

Более подробную информацию об этом можно найти в руководстве по организации очередей HTB Linux . Поэтому дерево на самом деле выглядит так:

       1: root qdisc (class htb)
     (100)
     / | \ 
    /  |  \
   /   |   \
 1:1  1:2  1:3    parent qdiscs (class htb)
(30)  (10)  (60)
 ||    ||    || -----> pfifo qdiscs (queue length: txqueuelen (default, can be changed by tc utitlity))

Обратите внимание, что параметр txqueuelen является параметром, -специфичным для интерфейса. Это означает, что параметр является свойством интерфейса и может быть изменен с помощью iproute2или ifconfig. По умолчанию его значение равно 1000. Вот пример того, как изменить его на 200 черезiproute2:

ip link set eth0 txqueuelen 200

Когда конечный узел создается (в контексте HTB qdisc ), pfifo qdisc по умолчанию присоединяется к листовому классу. Этот pfifo инициализируется с ограничением очереди txqueuelen интерфейса. Это можно найти в функции htb_change_class()в сч _htb.c ,строка 1395:

/* create leaf qdisc early because it uses kmalloc(GFP_KERNEL)
 * so that can't be used inside of sch_tree_lock
 * -- thanks to Karlis Peisenieks
 */
new_q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
                          classid, NULL);

Длину очереди по умолчанию для очереди pfifo см. в sch _fifo.c , строка 61 :

.

u32 limit = qdisc_dev(sch)->tx_queue_len;

Ядро напрямую взаимодействует с корневым qdisc (, может быть классовым или бесклассовым ), когда оно хочет поставить пакет в очередь или удалить из очереди. Если корневой qdisc является классовым и имеет потомков, то он сначала классифицирует пакет (и решает, какому потомку отправить пакет ). Исходный код ядра, где это делается:sch _htb.c , строка 209:

static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch,
                                      int *qerr)

Читая комментарии, можно легко сделать вывод, что эта функция возвращает одно из следующих:

  1. NULL, если пакет нужно отбросить

  2. -1, если пакет должен быть поставлен в очередь в прямую _очередь

  3. листовой узел (который содержит элементарный qdisc, где фактически заканчиваются пакеты )Эта функция проходит через все внутренние узлы (Классы )дерева пока он не вернет конечный узел, где пакет должен быть поставлен в очередь.

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

Прямая очередь:Это специальная внутренняя очередь fifo, поддерживаемая qdisc HTB, из которой пакеты удаляются из очереди с аппаратной скоростью. Длина его очереди равна txqueuelen. Пакет попадает в прямую очередь, если HTB не может отнести его к одному из дочерних qdisc, а значение по умолчанию не указано.

Итак, ответы на мои собственные вопросы:

  1. Да,поскольку они являются листовыми узлами, по умолчанию они являются очередями pfifo с длиной очереди txqueuelen интерфейса, которая по умолчанию равна 1000 и может быть изменена.

  2. Дисциплина обслуживания очередей подобна алгоритму вместе с очередью, объединенными в единый пакет! Если вы спросите меня, организация очереди является свойством как типа очереди, так и планировщика пакетов (, здесь планировщик пакетов означает алгоритм, который ставит пакет в очередь и удаляет из очереди ). Например, очередь может иметь тип pfifo или bfifo. Алгоритм, используемый для постановки в очередь и удаления из очереди, одинаков, но длина очереди измеряется в байтах для байта fifo (bfifo ). Пакеты сбрасываются в bfifo, когда достигается лимит байтов. Предел байтов по умолчанию рассчитывается как mtu*txqueuelen. Например, когда пакет ставится в очередь, длина пакета добавляется к текущей длине очереди. Точно так же, когда пакет исключен из очереди, длина пакета вычитается из длины очереди.

  3. Ответ выше.

Некоторые источники, к которым можно обратиться:

  1. Управление сетевым трафиком Linux — обзор реализации (PDF)

  2. Путешествие в центр ядра Linux :Управление трафиком, формирование и качество обслуживания

  3. Демистификация TC -Блог исследований и разработок Criteo

  4. Очередь в сетевом стеке Linux -Журнал Linux

7
28.07.2019, 11:43
7 ответов

Это можно сделать относительно легко, используя lsдля создания списка существующих каталогов, а затем переходя через xargsв команду tar.

раствор:

ls -d here_is_a_dir here_is_another_one yet_another_dir 2> /dev/null | xargs tar -czf archive.tgz

поломка:

  • ls -dтолько список каталогов
  • here_is_a_dir here_is_another_one yet_another_dirсписок каталогов для проверки
  • 2> /dev/nullнаправить stderr в /dev/null, чтобы мы получали только вывод stdout (нет отсутствующих каталогов)
  • | xargsпревращает список существующих каталогов из предыдущей команды в аргументы
  • tar -czf archive.tgzсоздать архив, используя аргументы
1
27.01.2020, 20:14

Если вы можете использовать bash, то с расширенной подстановкой(extglob):

$ shopt -s extglob; set -x
$ tar -czf archive.tgz *(here_is_a_dir|here_is_another_one|yet_another_dir)
+ tar -czf archive.tgz
tar: no files or directories specified

И если один или несколько из них существуют:

$ touch here_is_a_dir yet_another_dir
+ touch here_is_a_dir yet_another_dir
$ tar -czvf archive.tgz *(here_is_a_dir|here_is_another_one|yet_another_dir)
+ tar -czvf archive.tgz here_is_a_dir yet_another_dir
a here_is_a_dir
a yet_another_dir

(Я использовал set -x, чтобы вы могли видеть результаты расширения глобуса.)

3
27.01.2020, 20:14

Сzsh:

dirs_to_archive=(some/dir /some/other/dir and/more/dirs)
existing_dirs=($^dirs_to_archive(/N))
if (($#existing_dirs)); then
  tar -cf - -- $existing_dirs | xz > file.tar.xz
else
  echo >&2 Error: none of the dirs were found
fi

Эквивалент POSIX (, хотя обратите внимание, что ни tar, ни xzне являются командами POSIX. )будет чем-то вроде:

# The list of dirs in "$@" (the only array in POSIX sh language)
set -- some/dir /some/other/dir and/more/dirs

for dir do
  # remove from the array the elements that are not directories like with
  # zsh's / glob qualifier above
  [ -d "$dir" ] && [ ! -L "$dir" ] && set -- "$@" "$dir"
  shift
done
if [ "$#" -gt 0 ]; then
  tar -cf - -- "$@" | xz > file.tar.xz
else
  echo >&2 Error: none of the dirs were found
fi
7
27.01.2020, 20:14

Если у вас есть pax , вы можете использовать его для фильтрации того, что включается в архив. Pax предписывается POSIX как замена исторически разнообразным cpio и tar, но многие варианты Unix сопротивляются его принятию, и, в частности, BusyBox не имеет его.

В Pax есть функция исключения файлов, хотя она довольно скрыта в описании. Вы можете переименовывать файлы с помощью -s. Если вы переименуете файл в пустую строку, он будет исключен. При наличии нескольких опций -sдля каждого применяется первое совпадение, а фильтры переименования -sпропускаются. Таким образом, вы можете создать ряд правил включения/исключения, очень похожих на rsync . Правило включения в синтаксисе Pax —-s'!REGEX!&!'(переименовать в себя ), а правило исключения —-s'!REGEX!!'(переименовать в пустое ).

pax -w -x ustar \
    -s'!^\./here_is_a_dir$!&!' -s'!^\./here_is_a_dir/!&!' \
    -s'!^\./here_is_another_one$!&!' -s'!^\./here_is_another_one/!&!' \
    -s'!^\./yet_another_dir$!&!' -s'!^\./yet_another_dir/!&!' \
   . | gzip >archive.tgz

BSD tar имеет аналогичную -sопцию. С другой стороны, GNU tar и BusyBox tar не имеют возможности сделать это, включая/исключая гимнастику.

0
27.01.2020, 20:14

Вероятно, проще всего

find adir anotherdir yadir -maxdepth 0 2>&- | tar Tcf - my.tar
0
27.01.2020, 20:14

Если ваша версия tarподдерживает это, создайте пустой tar-файл и добавьте к нему по мере необходимости, используя -rвместо-c

touch foo.tar

for d in here_is_a_dir here_is_another_one yet_another_dir; do
  if [ -d "$d" ]; then
    tar -rf foo.tar "$d"
  fi
done
gzip foo.tar
0
27.01.2020, 20:14

Тот, который должен работать только с POSIX sh(tar.sh):

#!/bin/sh

first=1
for dir in "$@"; do
        if [ "$first" ]; then  # this is a bit ugly
                set --
                first=
        fi
        if [ -d "$dir" ]; then
                set -- "$@" "$dir"
        fi
done
echo tar -czf archive.tar.gz "$@"    # remove that 'echo'

Тест:

$ mkdir here_is_a_dir yet_another_dir
$./tar.sh here_is_a_dir here_is_another_one yet_another_dir
tar -czf archive.tar.gz here_is_a_dir yet_another_dir
0
27.01.2020, 20:14

Теги

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