Объединение отсортированных файлов с помощью fifos

#performance #bash #fifo

#Производительность #bash #fifo

Вопрос:

У меня есть несколько отсортированных файлов в папке gzipped. Как мне объединить некоторые из них в другой отсортированный архивированный файл? Прямо сейчас я использую явный fifos. Есть ли способ сделать это в bash без? Я немного новичок в bash, поэтому, пожалуйста, извините за отсутствие стиля.

 #!/bin/bash
# Invocation ./merge [files ... ]
# Turns an arbitrary set of sorted, gzipped files into a single sorted, gzipped file,
# printed to stdout. Redirect this script's output!
for f in $@
do
    mkfifo $f.raw
    gzcat $f > $f.raw amp;
    # sort -C $f.raw
done
sort -mu *.raw | gzip -c # prints to stdout.
rm -f *.raw
  

Я хочу преобразовать это во что-то вроде…

 sort -mu <(gzcat $1) <(gzcat $2) <(gzcat $3) ... | gzip -9c # prints to stdout.
  

…но не знаю как. Нужен ли мне цикл, преобразующий параметры в строку? Есть ли какой-нибудь волшебный ярлык для этого? Возможно map gzcat $@ ?

ПРИМЕЧАНИЕ: Объем каждого из файлов превышает 10 ГБ (и 100 ГБ распакованы). У меня накопитель объемом 2 ТБ, так что на самом деле это не проблема. Кроме того, эта программа ДОЛЖНА выполняться в O (n), иначе это становится невозможным.

Комментарии:

1. Я вижу, вы отредактировали вопрос, пока я отвечал — да, вам нужен цикл для построения командной строки и либо eval , либо bash -c "$cmd" для ее выполнения в конце.

Ответ №1:

Вы можете объединить eval и «подстановку процесса» с помощью Bash. Предполагая, что основные имена файлов не содержат пробелов (что, учитывая, что вы используете $@ вместо "$@" , вероятно, имеет место), тогда что-то вроде:

 cmd="sort -mu"
for file in "$@"
do cmd="$cmd <(gzip -cd $file)"
done
eval $cmd | gzip -c9 > outputfile.gz
  

Вы также можете использовать bash -c "$cmd" вместо eval $cmd в последней строке. Если в именах файлов есть пробелы, вам придется поработать немного усерднее. Это работает, если имена не содержат одинарных кавычек:

 cmd="sort -mu"
for file in "$@"
do cmd="$cmd <(gzip -cd '$file')"
done
eval $cmd | gzip -c9 > outputfile.gz
  

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

Ответ №2:

Для меня ваш вопрос немного неясен, но если я понимаю ваши потребности, попробуйте это:

 gunzip -c file1 file2 .... | sort | gzip -9 > mergedFile.gz
  

Если вы хотите поместить все файлы определенного типа в 1 каталог, то вы можете использовать file*.type в качестве входного списка для gunzip, в противном случае, согласно моему примеру, вам нужно будет явно перечислить каждый файл.

-c Опция указывает «отправить выходные данные в стандартный вывод», который является прочитанным каналом, отправленным в sort , который отправляет свои выходные данные в стандартный вывод, канал и в gzip, при этом его стандартный вывод перенаправляется в конечный файл. -9 Выполняется максимальное сжатие, при котором получается файл наименьшего размера (для gzip), но занимает больше времени. Вы можете указать явное число от -1 до -9, чтобы настроить размер сжатия / время сжатия в соответствии с вашими потребностями.

Я надеюсь, что это поможет.

Комментарии:

1. Я действительно хочу использовать sort -mu, который не будет работать, если мы запустим архив за один раз. Это превращает сортировку из O (nlogn) в O (n).

2. Обычно я бы использовал явное gzip -c -9 , но, думаю, это сработает.

3. Итак, у вас есть большие файлы, и вы ищете способ распараллелить процесс, предварительно отсортировав файлы меньшего размера, а затем объединив их в конце? И у вас есть несколько процессоров, которые вы можете назначить каждому процессу сортировки меньшего размера? Вы хотите сэкономить время, процессор или??? Здесь, на S.O., есть значительное количество людей, заинтересованных в настройке производительности. Вы можете добавить тег для сравнительного анализа, тестирования, настройки производительности, чтобы получить лучший совет о том, как подойти к этому. Удачи.

4. @shellter: Готово. Спасибо. Но я больше искал надежный способ создания fifos (который нельзя сломать нажатием [file].raw), чем для настройки производительности. Может быть, что-то вроде замены команд? linuxjournal.com/article/2156?page=0,1

5. Хорошо, это интересный вопрос, но я хотел бы, чтобы это было в вашем первоначальном вопросе. Мне никогда не приходилось сталкиваться с этим, поэтому у меня нет хорошего ответа. Я полагаю, недостаточно установить 600 разрешений для fifo? Как произойдет «касание» файла? Можете ли вы сделать свое имя fifo более уникальным, добавив к нему ProcessId ($ $)? Что случилось с вашим беспокойством по поводу O (nlogn) против O (n)? Спокойной ночи.

Ответ №3:

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

Вот способ избежать одинарных кавычек в именах файлов (или путях к файлам), которые будут eval ‘редактироваться в переменных, заключенных в одинарные кавычки.

 (
esc="'''"
file="/Applications/iWork '09/Pages.app"
file="${file//'/${esc}}"
#echo "'${file}'"; ls -bdl "'${file}'"
evalstr="echo '${file}'; ls -bdl '${file}'"
#set -xv
eval "${evalstr}"
)