4

Я работаю с несколькими файлами, расположенными в разных каталогах, которые мне нужно сжать в отдельные файлы .gz. Мне также нужно переместить сжатые файлы в один каталог, оставив оригиналы в покое.

Есть ли способ сделать это с помощью команды gzip и файла, который содержит список всех путей к файлам, которые я хочу сжать?

Извиняюсь, если это немного затянуто ...Я довольно новичок в Linux и не могу придумать более эффективный способ сформулировать это.

2 ответа2

4

Предполагая, что список файлов хранится в файле с именем filelist (ровно один путь к файлу на строку), и вы хотите сохранить сжатые файлы в zipdir, этот скрипт bash достигнет желаемых результатов:

#!/bin/bash

while IFS= read file; do
    gzip -c "$file" > "zipdir/$(basename "$file").gz"
done < filelist

В bash/dash вы также можете преобразовать вышеприведенное в однострочное:

while IFS= read file; do gzip -c "$file" > "zipdir/$(basename "$file").gz"; done < filelist

В других оболочках (например, tcsh или zsh)

bash -c 'while IFS= read file; do gzip -c "$file" > "zipdir/$(basename "$file").gz"; done < filelist'

сделаю работу.

Если bash отсутствует, его можно заменить на dash.

Как это устроено

  • ... < filelist перенаправляет содержимое списка файлов в ...

  • while IFS= read file; do ... done просматривает строки в filelist, сохраняет содержимое текущей обработанной строки в файле переменных и выполняет ...

    IFS= изменяет внутренний разделитель файлов. Это необходимо для правильной обработки нескольких, ведущих и конечных пробелов.

  • gzip -c "$file" > "zipdir/$(basename "$file").gz" сжимает текущий обработанный файл и сохраняет выходные данные в файле с тем же именем и расширением .gz в каталоге zipdir.

    Здесь basename "$file" извлекает пустое имя файла из пути к файлу.

0

Я не думаю, что gzip поддерживает пути чтения из файла. Обходной путь может состоять в том, чтобы либо поместить все целевые файлы в архив (tar), либо выполнить его несколько раз.

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

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

Создать структуру папок

TARGET=~/tmp/out

while read line; do 
    dirname "$line" ; 
done < list.txt | sort -u |
xargs -I%  echo mkdir -p "$TARGET/%"

  ## out: ##
  mkdir /home/jaroslav/tmp/out/code/bash 
  mkdir /home/jaroslav/tmp/out/recipes
  mkdir /home/jaroslav/tmp/out/samba
  mkdir /home/jaroslav/tmp/out/wikipedia

Копировать файлы

while read line; do
   gzip -c "$SOURCE/$line" > "$TARGET/$line.gz"
done < list.txt

команды

  • dirname: удалить последнюю часть пути к файлу, оставив каталог
  • read [arg] <file: читать по одной строке из файла и сохранять ее в переменной оболочки arg
  • сортировать -u: удалить дубликаты записей (оставить u Nique)
  • xargs -I%: выполнить команду (echo ....) один раз для каждого элемента (имя dir) из канала (|)
  • gzip -c in> out: сжатие и запись в стандартный вывод (-c). > перенаправляет стандартный ввод в файл с именем out.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .