Як зняти розпакування, de-tar -xvf - знеструмити в брудній папці?


14

Зазвичай, я забороняю те, що $ mkdir newFolder; $ mv *.zip newFolder; $ cd newFolder; $unzip *.zipіноді я лінуюсь, але іноді я лінуюсь і просто роблю у довільній папці, $ unzip *.zipщоб час від часу псуватися з іншим вмістом. Я перерахую тут деякі методи - деякі архівні версії, безумовно, мають crappy-flags, а інші більш спартанські, мене більше цікавить останній.

Деякі способи знеструмлення, чи є інші?

  1. $ find . -anewer fileThatExistedBeforeUnarchieving -ok rm '{}' \;Слабкі сторони полягають у тому, що в ньому перераховані *.zipбруски, тому потрібно використовувати повільно -ok, повільно з багатьма *.zipсірниками і, чомусь, схоже, це не відповідає усьому видобутому.

  2. Якщо невелика кількість вилучених файлів, одна за одною, повільна, громіздка і схильна до помилок.

  3. Коли я хочу переконатися, що вміст архіву насправді папка, я іноді перевіряю $ unzip -l *.bsd, чи працює принаймні в obsd`s unzip-версії.

Якщо ви посилаєтесь на певні засоби архівації, будь ласка, вкажіть їх, коли це доречно. Нехай це все буде просто - мене більше цікавлять ШЛЯХИ, як ви це робите, а не один інструмент.



Ось сценарій, який я використовую для автоматизації mkdir; unzipматеріалів, тому я ніколи не лінуюся це робити! svn.mikelward.com/svn/scripts/untar
Мікель

2
Дивіться відповідне запитання та відповіді: unix.stackexchange.com/questions/5123/…
alex

Відповіді:


11

По імені

Ви можете генерувати список файлів в архіві та видаляти їх, хоча це дратує навпаки архіваторів, таких як unzip або 7z, у яких немає можливості генерувати звичайний список імен файлів. Навіть з tar, це передбачає, що в іменах файлів немає нових рядків.

tar tf foo.tar | while read -r file; do rm -- "$file" done
unzip -l foo.zip | awk '
    p && /^ --/ {p=2}
    p==1 {print substr($0, 29)}
    /^ --/ {++p}
' | while …
unzip -l foo.zip | tail -n +4 | head -n -2 | while …  # GNU coreutils only
7z l -slt foo.zip | sed -n 's/^Path = //p' | while …  # works on tar.*, zip, 7z and more

Замість того, щоб видаляти файли, ви можете перемістити їх за призначенням.

tar tf foo.tar | while read -r file; do
  if [ -d "$file" ]; then continue; fi
  mkdir -p "/intended/destination/${file%/*}"
  mv -- "$file" "/intended/destination/$file"
done

Використання FUSE

Замість того, щоб залежати від зовнішніх інструментів, ви можете (на більшості об'єктів) використовувати FUSE для маніпулювання архівами за допомогою звичайних команд файлової системи.

Ви можете використовувати Fuse-zip, щоб зазирнути у блискавку, витягнути її cp, перелічити її вміст findтощо.

mkdir /tmp/foo.d
fuse-zip foo.zip /tmp/foo.d
## Remove the files that were extracted mistakenly (GNU/BSD find)
(cd /tmp/foo.d && find . \! -type d -print0) | xargs -0 rm
## Remove the files that were extracted mistakenly (zsh)
rm /tmp/foo.d/**(:"s~/tmp/foo.d/~~"^/)
## Extract the contents where you really want them
cp -Rp /tmp/foo.d /intended/destination
fusermount -u foo.d
rmdir foo.d

AVFS створює перегляд всієї ієрархії каталогів, де всі архіви мають пов'язаний каталог (те саме ім'я з # позначено в кінці), який, як видається, містить вміст архіву.

mountavfs
## Remove the files that were extracted mistakenly (GNU/BSD find)
(cd ~/.avfs/"$PWD/foo.zip#" && find . \! -type d -print0) | xargs -0 rm
## Remove the files that were extracted mistakenly (zsh)
rm ~/.avfs/$PWD/foo.zip\#/**/*(:"s~$HOME/.avfs/$PWD/foo.zip#~~"^/)
## Extract the contents where you really want them
cp -Rp ~/.avfs/"$PWD/foo.zip#" /intended/destination
umountavfs

За датою

Якщо припустити , що не було іншої якої - небудь діяльності в тій же ієрархії , ніж ваш екстрагування, ви можете сказати , розпаковані файли їх недавнім CTime . Якщо ви тільки що створили або перемістили zip-файл, ви можете використовувати його як обрізання; в іншому випадку використовуйте ls -lctrдля визначення відповідного часу відсічення. Якщо ви хочете переконатись, що не знімати блискавки, немає ніяких причин робити будь-яке затвердження вручну: findцілком здатне їх виключити. Ось приклади команд, що використовують zsh або find; зауважте, що -cminі -cnewerпраймери не в POSIX, але існують на Linux (та інших системах з GNU знайти), * BSD та OSX.

find . \! -name '*.zip' -type f -cmin -5 -exec rm {} +  # extracted <5 min ago
rm **/*~*.zip(.cm-6)  # zsh, extracted ≤5 min ago
find . -type f -cnewer foo.zip -exec rm {} +  # created or moved after foo.zip

За допомогою пошуку GNU, FreeBSD та OSX, інший спосіб визначити час відсікання - створити файл і використовувати touchдля встановлення його mtime на час відсічення.

touch -d … cutoff
find . -type f -newercm cutoff -delete

Замість того, щоб видаляти файли, ви можете перемістити їх за призначенням. Ось спосіб пошуку GNU / * BSD / OSX, створення необхідних каталогів за призначенням.

find . \! -name . -cmin -5 -type f -exec sh -c '
    for x; do
      mkdir -p "$0/${x%/*}"
      mv "$x" "$0/$x"
    done
  ' /intended/destination {} +

Zsh еквівалент (майже: цей відтворює всю ієрархію каталогів, а не лише каталоги, які містять файли):

autoload zmv
mkdir -p ./**/*(/cm-3:s"|.|/intended/destination|")
zmv -Q '(**/)(*)(.cm-3)' /intended/destination/'$1$2'

Попередження, я не перевірив більшість команд у цій відповіді. Завжди переглядайте список файлів перед видаленням (запустіть echoспочатку, потім, rmякщо це нормально).


Я нарешті сьогодні стикаюся з цією проблемою. Як корінь! Врешті-решт я використав комбінацію "По імені" та "За датою"
phunehehe

1

Я почуваюся дурним, все одно я почухав голову, щоб написати цей сценарій, коли у мене була подібна проблема. Я cpioз -itпрапором , щоб отримати список файлів; ви можете використовувати еквівалентні команди для інших архіваторів. Найскладніша частина полягає в тому, що архів cpio - з initrd, і я витягнув його /, тому багато папок і файлів мають те саме ім'я, що і в робочій системі. На щастя, cpio не перезаписав жоден із моїх існуючих файлів. Я використовую перевірку часу, щоб не видалити нічого, що існувало до неправильної команди.

#! /bin/sh

files=$(cpio -it < /mnt/temp/lglive.cpio)

for i in ${files}
do
    name=$(stat -c "%n" ${i})
    time=$(stat -c "%Y" ${i})
    # Time of the creation of the mess: 1296457595
    if [[ ${time} -gt 1296457590 && ${time} -lt 1296457600 ]]
    then
        if [[ -f ${name} ]]
        # If it is a file, it must have been created as part of the mess.
        then
            echo "rm ${name}"
        elif [[ -d ${name} ]]
        # If it is a directory, it may have been part of the mess
        # or maybe some files underneath it is created as part of the mess.
        then
            if [[ $(ls -A ${name}) ]]
            # If the directory contains something then don't delete it.
            then
                echo "${name} is not empty"
            # If the directory is empty then assume it is rubbish.
            else
                echo "rmdir ${name}"
            fi
        fi
    fi
done

echo "Files and directories still exist after the removal:"
for i in ${files}
do
    if [[ -e ${i} ]]
    then
        echo ${i}
    fi
done

0

Як щодо подачі списку файлів в архів xargs rm?

Це було б tar -tf tarbomb.tar | xargs rmабо unzip --list zipbomb.zip | xargs rm.


2
Команди, задані, не працюватимуть у загальному випадку, і це небезпечно, оскільки ви видаляєте файли. xargsочікує, що його вклад буде процитований своєрідним чином, findякий не дає результату. Використовуйте xargs -I rm {}так, щоб xargs обробляв один елемент на рядок. Що стосується команди unzip, яка у вас реалізація? Mine (Debian / Ubuntu) НЕ --listтільки -l, і це не просто надрукувати імена файлів, так що додаткова обробка не потрібна.
Жил 'ТАК - перестань бути злим'

@Gilles: 1) так, це небезпечно, але оскільки ми, мабуть, перезаписали оригінальні файли - їх уже немає. 2) Я не говорив про це find. 3) Ви маєте рацію unzip, я не тестував, і, здається, немає варіанту для неоформленого переліку. Ні --listна моєму Ubuntu також - я просто не тестував.
alex

До жаль про консервований відповідь замінити tar -tна find. Але мої інші моменти стоять. Існує реальний ризик, що ваша команда як дана видалить непов'язаний файл.
Жил "ТАК - перестань бути злим"

tar -tf tarbomb.tarбуде друкувати імена файлів по одному на рядок, так що ви можете зробити tar -tf tarbomb.tar | while IFS=$'\n' read -r filename; do rm "$filename"; doneчи подібне.
Мікель

0

Насправді не те, про що ви просили, але про те, як використовувати сценарій "розпакування всіх" замість.

unzip *.zip

Таким чином, вихід з кожного файлу переходить у власну директорію.

#!/bin/bash
for f in *.zip ; do unzip -n "$f" -d "${f/%zip/out}"; done

0

Я використовую таку функцію в zsh:

ununzip () {
    rm -r $(unzip -l $1 | grep -v 'Archive:' | \
    grep '[/.]' | sed 's![^a-zA-Z]([a-zA-Z./])!\1!')
}

Тобто заміна команди для видалення всіх файлів з очищеного виводу unzip -l.

tar tvf може бути використаний аналогічним чином.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.