ฉันจะกรองเนื้อหาของไฟล์ tar สร้างไฟล์ tar อื่นในไพพ์ได้อย่างไร


13

พิจารณาไฟล์ tar เดียวจากระบบภายนอกซึ่งมีบางไดเรกทอรีที่มีคุณลักษณะต่าง ๆ ที่ฉันต้องการเก็บไว้เช่นการอนุญาต, mtimes เป็นต้นฉันจะนำชุดย่อยของไฟล์เหล่านี้มาเป็นผู้ใช้ปกติได้อย่างไร (ไม่ใช่รูท)?

กำลังมองหาสิ่งที่ชอบ:

tar -f some.tar.gz --subset subdir/ | ssh remote@system tar xvz

นอกจากนี้ยังจำเป็นที่จะต้องรักษาแอตทริบิวต์หลัก (ความเป็นเจ้าของกลุ่มโหมด mtime) ในไฟล์เก็บถาวร tar นี้ สิ่งที่เกี่ยวกับคุณลักษณะอื่น ๆ ในไฟล์ tar เช่นคำหลักส่วนหัวขยาย ?

คะแนนโบนัสสำหรับโซลูชันที่หลีกเลี่ยงการใช้ไดเรกทอรีชั่วคราวในกรณีที่ subdir นี้มีไฟล์ขนาดใหญ่

คำตอบ:


14

bsdtar (ขึ้นอยู่กับ libarchive)สามารถกรอง tar (และคลังเก็บอื่น ๆ ) จาก stdin ถึง stdout ตัวอย่างเช่นสามารถส่งผ่านเฉพาะชื่อไฟล์ที่ตรงกับรูปแบบและสามารถs/old/new/เปลี่ยนชื่อได้ มันบรรจุอยู่แล้วสำหรับ distros ส่วนใหญ่เช่นbsdtarใน Ubuntu

sudo apt-get install bsdtar   # or aptitude, if you have it.

# example from the man page:
bsdtar -c -f new.tar --include='*foo*' @old.tgz
#create new.tar containing only entries from old.tgz containing the string ‘foo’
bsdtar -czf - --include='*foo*' @-  # filter stdin to stdout, with gzip compression of output.

โปรดทราบว่ามีรูปแบบการบีบอัดให้เลือกมากมายสำหรับอินพุต / เอาท์พุตดังนั้นคุณไม่ต้องไปป์ด้วยตนเองผ่าน gunzip / lz4 ด้วยตนเอง คุณสามารถใช้-สำหรับ stdin ด้วย@tarfileไวยากรณ์และ / หรือ-สำหรับ stdout เหมือนปกติ


การค้นหาของฉันยังพบเครื่องมือแก้ไข tar สตรีมมิ่งนี้ซึ่งต้องการให้คุณกำหนดการเปลี่ยนแปลงที่เก็บถาวรที่คุณต้องการโดยใช้จาวาสคริปต์ (ฉันคิดว่าสิ่งทั้งหมดเขียนด้วย js)

https://github.com/mafintosh/tar-stream


1
ยอดเยี่ยมไม่รู้ว่า@original.tarวิธีนี้เป็นไปได้ด้วย bsdtar ดูเหมือนว่าจะทำงานกับคุณลักษณะที่เพิ่มขึ้นและการบีบอัดเช่นกัน</var/cache/pacman/pkg/libuv-1.7.0-1-x86_64.pkg.tar.xz bsdtar -czf - --include='usr/share/*' @- | tar tvz(และด้วยเหตุผลบางอย่างการเลือกที่ว่างเปล่าจะสร้างชุดของศูนย์ไบต์ แต่นั่นไม่ใช่ปัญหาสำคัญสำหรับฉัน)
Lekensteyn

1
จากการทดสอบของฉันs/old/new/ ไม่ทำงานกับไฟล์ที่มาจากไฟล์เก็บถาวรเก่าโดยใช้ @ old.tgz มันทำงานได้กับไฟล์จริงเท่านั้นเก็บถาวรโดยตรงจากระบบไฟล์ มันเป็นความอัปยศจริงๆเพราะเป็นกรณีการใช้งานที่มีประโยชน์ที่สุดสำหรับฉัน
บาร์ต

4

วิธีที่ง่ายที่สุดคือการคัดลอกไฟล์เก็บถาวรทั้งหมด ฉันคิดว่าคุณไม่ต้องการทำเช่นนั้นเพราะมันใหญ่เกินไป

เครื่องมือบรรทัดคำสั่งปกติ ( tar, pax) ไม่สนับสนุนการคัดลอกสมาชิกของไฟล์เก็บถาวรไปยังไฟล์เก็บถาวรอื่น

หากคุณไม่ต้องการรักษาความเป็นเจ้าของฉันขอแนะนำให้ใช้ระบบไฟล์FUSE คุณสามารถใช้archivemountจะติดที่เก็บเป็นระบบแฟ้ม; ทำสิ่งนี้เพื่อเก็บถาวรซอร์สและรัน tar บนระบบไฟล์ที่เมาท์

archivemount some.tar.gz mnt
cd mnt
tar -cz subdir | ssh example.com tar -xz
fusermount -u mnt

หรือคุณสามารถใช้AVFS :

mountavfs
cd ~/.avfs$PWD/some.tar.gz\#
tar -cz subdir | ssh example.com tar -xz

หรือคุณสามารถเรียกใช้tarในการเก็บและสารสกัดจากเดิมไปยังเครื่องระยะไกลผ่านSSHFS

sshfs example.com: mnt
cd mnt
tar -xf /path/to/some.tar.gz subdir
fusermount -u mnt

อย่างไรก็ตามวิธีการทั้งหมดนี้ยุ่งยากหากคุณต้องการรักษาความเป็นเจ้าของ พวกเขาทั้งหมดเกี่ยวข้องกับการแยกไฟล์ในเครื่องท้องถิ่นดังนั้นความเป็นเจ้าของไฟล์นี้จะต้องเป็นเจ้าของระยะไกลที่ตั้งใจไว้ สิ่งนี้ต้องการการทำงานในฐานะรูทและอาจไม่ให้ผลลัพธ์ตามที่ตั้งใจหากไฟล์นั้นเป็นของบัญชีที่มีชื่อหรือรหัสที่แตกต่างกันระหว่างเครื่องโลคอลและรีโมตโฮสต์

tarfileไลบรารีของ Python มีวิธีที่ง่ายในการจัดการสมาชิก tar ดังนั้นคุณสามารถสับเปลี่ยนจากไฟล์ tar หนึ่งไปยังอีกไฟล์หนึ่งได้ สนับสนุนรูปแบบมาตรฐาน POSIX (ustar, pax) รวมถึง GNU บางส่วน นี่คือสคริปต์ Python ที่ยังไม่ทดลองซึ่งอ่านไฟล์ tar (อาจบีบอัดด้วย gzip หรือ bzip2) ในอินพุตมาตรฐานและเขียนไฟล์ tar ที่บีบอัดด้วย bzip2 บนเอาต์พุตมาตรฐาน สมาชิกจากแหล่งที่มาจะถูกคัดลอกหากพวกเขาเริ่มต้นด้วยการโต้แย้งส่งผ่านไปยังสคริปต์

#!/usr/bin/env python2
import sys, tarfile
source = tarfile.open(fileobj=sys.stdin)
destination = tarfile.open(fileobj=sys.stdout, mode='w:bz2')
for info in source:
    if info.name.startswith(sys.argv[1]):
        destination.addfile(info)
destination.close()

ที่จะเรียกว่า

tar_filter <some.tar.gz subdir/ | ssh example.com tar -xj

1
bsdtar (ขึ้นอยู่กับการเก็บถาวร) สามารถกรอง tar เก็บได้ทันทีดูคำตอบของฉัน
Peter Cordes

ภารกิจคือการดึงข้อมูลจากอิมเมจเฟิร์มแวร์ดังนั้นการเป็นเจ้าของ / กลุ่มสมาชิกจึงมีความสำคัญ วิธีการที่หลามสามารถทำงานได้
Lekensteyn

0

อีกวิธีหนึ่งที่ใช้สิทธิ์น้อยกว่าคือการใช้fakerootโปรแกรมเพื่อหลอกว่าคุณได้รับอนุญาตให้เปลี่ยนความเป็นเจ้าของ ในขณะที่คุณสมบัติ tar อื่น ๆ จะหายไปมันจะเก็บโหมด mtime และ uid / gid คำสั่งเหล่านี้สร้างไดเรกทอรีชั่วคราวแยกชุดย่อยของไฟล์และสร้างไฟล์เก็บถาวรใหม่:

mkdir tmp
<some.tar.gz \
fakeroot -- sh -c 'cd tmp && tar -xzf- subdir/ && tar -czf- subdir' |
   ssh remote@system tar -xzvf-
rm -rf tmp

0

GNU tarมี--deleteตัวเลือก:

$ tar -c a b c | tar --delete a | tar -t
b
c

ด้วยวิธีนี้คุณจะได้รับเซตย่อยของ tar น้ำมันดินโดยการระบุสิ่งที่จะไม่รวมในเอาท์พุท

น่าเสียดายที่ฉันไม่สามารถ--excludeเลือกใช้งานได้--deleteดังนั้นดูเหมือนว่าคุณต้องได้รับรายการที่ชัดเจน ( -t) ของสิ่งต่าง ๆ ที่จะลบแล้วส่งต่อไปยังการเรียกใช้อีกtarครั้ง

$ tar --delete --no-recursion `tar -t --exclude subdir <some.tar` <some.tar | ssh ...

หรือคุณสามารถเก็บรายการไว้ในไฟล์ภายนอกได้ถ้ามันยาวหรือซับซ้อนเกินไป:

$ tar -t --exclude subdir <some.tar >to_delete.lst
$ tar --delete --no-recursion -T to_delete.lst <some.tar | ssh ...

-1

จากสิ่งที่ฉันรู้tarคำสั่งไม่สามารถใช้รูปแบบ tar ทั้งเป็นอินพุตและเอาต์พุต คุณจะต้องแตกไฟล์ของคุณแบบโลคัลและใช้ tar อีกครั้งเพื่อสร้าง tarfile on-the-fly ด้วยสิ่งนี้ ( -หมายถึงใช้อินพุต / เอาท์พุตมาตรฐานแทนไฟล์):

tar cf - subdir/ | ssh remote@system 'cd extractdir && tar xvf -'

โปรดทราบว่าการtarที่สามารถสกัด tarfile ได้โดยตรงใน tarfile อื่นนั้นเป็นแนวคิดที่น่าสนใจ ...


หากไม่มีรูทข้อมูลนี้จะสูญเสียข้อมูลความเป็นเจ้าของ / กลุ่มทั้งหมดที่ฉันต้องการเก็บไว้อย่างชัดเจน
Lekensteyn

1
คุณควรแก้ไขคำถามของคุณเพื่อระบุว่าคุณไม่มีสิทธิ์เข้าถึงรูทบนโฮสต์ของคุณ
Uriel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.