ในสถานที่เก็บสารสกัด tar


14

ฉันมีภาวะที่กลืนไม่เข้าคายไม่ออกที่นี่ ...

ฉันต้องการย้ายไฟล์ประมาณ 70 GB จากเซิร์ฟเวอร์หนึ่งไปยังอีกเซิร์ฟเวอร์หนึ่งดังนั้นฉันตัดสินใจว่าการรวมไฟล์เหล่านั้นและการส่งไฟล์เก็บถาวรเป็นวิธีที่เร็วที่สุด

อย่างไรก็ตามเซิร์ฟเวอร์ที่รับจะมีพื้นที่เหลือเพียง 5 GB หลังจากได้รับไฟล์เก็บถาวร tar เท่านั้น

มีวิธีใดบ้างที่ฉันสามารถแยก tar 'in-place'? ฉันไม่จำเป็นต้องเก็บถาวรหลังจากถูกแยกออกมาดังนั้นฉันจึงสงสัยว่าเป็นไปได้ไหมที่จะทำเช่นนี้

แก้ไข:ควรสังเกตว่าที่เก็บถาวรได้ถูกส่งไปแล้วและฉันต้องการหลีกเลี่ยงการส่งอีกครั้งด้วยวิธีอื่น

คำตอบ:


11
% tar czf - stuff_to_backup | ssh backupmachine tar xvzf -

แปลเป็น:

  • tar และบีบอัด 'stuff_to_backup' ถึง stdout
  • เข้าสู่ระบบเพื่อ 'backupmachine' ผ่านทาง ssh
  • เรียกใช้ 'tar' บน 'backupmachine' และล้างสิ่งที่มาจาก stdin

ฉันเองจะใช้ 'rsync over ssh' เพื่อถ่ายโอนข้อมูลเพราะคุณสามารถถ่ายโอนข้อมูลต่อไปหากการเชื่อมต่อหยุดลง:

% rsync -ar --progress -e 'ssh' 'stuff_to_backup' user@backupmachine:/backup/

ซึ่งจะโอนทุกอย่างจาก 'stuff_to_backup' ไปยังโฟลเดอร์ 'backup' ที่ 'backupmachine' หากการเชื่อมต่อขาดเพียงแค่ทำซ้ำคำสั่ง หากบางไฟล์ในการเปลี่ยนแปลง 'stuff_to_backup' ให้ทำซ้ำเนื้อหานั้นจะมีการถ่ายโอนความแตกต่างเท่านั้น


ดูคำถามที่แก้ไขของฉัน
คนขี้ขลาดนิรนาม

@ Charlie Somerville: ใช่แล้วคุณได้ทิ้งส่วนที่สำคัญไว้ตั้งแต่แรก :)
akira

6

หากเครื่องอื่นมี ssh ฉันขอแนะนำให้คุณ rsync เป็นอีกทางเลือกหนึ่งที่ไม่ได้ใช้ไฟล์ tar:

rsync -avPz /some/dir/ user@machine:/some/other/dir/

และระวังด้วยความเป็นผู้นำ /

แก้ไขการอัปเดต

ดีฉันเห็นว่าตอนนี้มันเป็นของดองที่ดีถ้าคุณไม่สามารถลบและแนะนำด้วย rsync ฉันอาจจะลองแยกเลือกและลบจากน้ำมันดิน

สารสกัดที่เลือก:

$ tar xvf googlecl-0.9.7.tar googlecl-0.9.7/README.txt
googlecl-0.9.7/README.txt

เลือกลบ:

$ tar --delete --file=googlecl-0.9.7.tar googlecl-0.9.7/README.txt

อย่างไรก็ตามดูเหมือนว่าคุณจะใช้เวลาเขียนสคริปต์สำหรับสิ่งนี้ ...


ดูคำถามที่แก้ไขของฉัน
คนขี้ขลาดนิรนาม

ดูคำตอบที่แก้ไขของฉัน ... ขอให้โชคดี: - /
YuppieNetworking

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

1
@Charlie Somerville: คุณอาจต้องเริ่มต้นด้วยไฟล์ที่เก็บไว้ที่ท้าย tar มิฉะนั้นคุณอาจจบด้วย tar สร้างไฟล์เก็บถาวรใหม่ ... ดังนั้นให้ลบไฟล์ออกจากท้าย tar ก่อน
akira

5

โดยทั่วไปสิ่งที่คุณต้องการคือความเป็นไปได้ในการไพพ์ไฟล์ลงใน tar และ "lop" ด้านหน้าตามที่คุณไป

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

โซลูชันที่ 1

ระดับของการอ้อมจะแก้ปัญหาทุกปัญหา ขั้นแรกให้ย้อนกลับไฟล์ในตำแหน่งจากนั้นอ่านย้อนหลัง (ซึ่งจะส่งผลให้อ่านไฟล์ต้นฉบับไปข้างหน้า) และตัดส่วนท้ายของไฟล์ที่กลับด้านในขณะที่คุณไป

คุณจะต้องเขียนโปรแกรม (c, python, อะไรก็ตาม) เพื่อแลกเปลี่ยนจุดเริ่มต้นและจุดสิ้นสุดของไฟล์, การแบ่งข้อมูลตามกลุ่มและจากนั้นไพพ์ชิ้นส่วนเหล่านี้เพื่อ tar ในขณะที่ตัดทอนไฟล์ทีละชิ้น นี่เป็นพื้นฐานสำหรับโซลูชัน 2 ซึ่งอาจใช้งานง่ายกว่า

โซลูชันที่ 2

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

แยกไฟล์ archive.tar:

archive="archive.tar"
chunkprefix="chunk_"
# 1-Mb chunks :
chunksize=1048576

totalsize=$(wc -c "$archive" | cut -d ' ' -f 1)
currentchunk=$(((totalsize-1)/chunksize))
while [ $currentchunk -ge 0 ]; do
    # Print current chunk number, so we know it is still running.
    echo -n "$currentchunk "
    offset=$((currentchunk*chunksize))
    # Copy end of $archive to new file
    tail -c +$((offset+1)) "$archive" > "$chunkprefix$currentchunk"
    # Chop end of $archive
    truncate -s $offset "$archive"
    currentchunk=$((currentchunk-1))
done

ไพพ์ไฟล์เหล่านั้นลงใน tar (โปรดทราบว่าเราต้องการตัวแปร chunkprefix ในเทอร์มินัลที่สอง):

mkfifo fifo
# In one terminal :
(while true; do cat fifo; done) | tar -xf -
# In another terminal :
chunkprefix="chunk_"
currentchunk=0
while [ -e "$chunkprefix$currentchunk" ]; do
    cat "$chunkprefix$currentchunk" && rm -f "$chunkprefix$currentchunk"
    currentchunk=$((currentchunk+1))
done > fifo
# When second terminal has finished :
# flush caches to disk :
sync
# wait 5 minutes so we're sure tar has consumed everything from the fifo.
sleep 300
rm fifo
# And kill (ctrl-C) the tar command in the other terminal.

เนื่องจากเราใช้การตั้งชื่อไปป์ ( mkfifo fifo) คุณไม่จำเป็นต้องไปที่ชิ้นส่วนทั้งหมดพร้อมกัน สิ่งนี้มีประโยชน์หากคุณมีพื้นที่ จำกัด จริงๆ คุณสามารถทำตามขั้นตอนต่อไปนี้:

  • ย้ายพูดชิ้นขนาด 10Gb สุดท้ายไปยังดิสก์อื่น
  • เริ่มการสกัดด้วยชิ้นที่คุณยังมี
  • เมื่อwhile [ -e … ]; do cat "$chunk…; doneลูปเสร็จสิ้น (เทอร์มินัลที่สอง):
  • อย่าหยุดtarคำสั่งอย่าลบ Fifo (เทอร์มินัลแรก) แต่คุณสามารถรันได้syncในกรณีที่
  • ย้ายไฟล์ที่แตกแล้วซึ่งคุณรู้ว่าสมบูรณ์แล้ว (tar ไม่รอจนกว่าข้อมูลจะเสร็จสิ้นการแยกไฟล์เหล่านี้) ไปยังดิสก์อื่น
  • ย้ายชิ้นส่วนที่เหลือกลับไป
  • ทำการแยกต่อโดยรันwhile [ -e … ]; do cat "$chunk…; doneบรรทัดอีกครั้ง

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

คุณจะไม่มีทางรู้ว่าเทอร์มินัลตัวแรก ( tar) ได้ทำการประมวลผลเนื้อหาของ Fifo จริงหรือไม่ดังนั้นถ้าคุณต้องการคุณสามารถรันสิ่งนี้แทนได้ แต่คุณไม่มีความเป็นไปได้ที่จะแลกเปลี่ยนชิ้นส่วนกับดิสก์อื่นอย่างราบรื่น:

chunkprefix="chunk_"
currentchunk=0
while [ -e "$chunkprefix$currentchunk" ]; do
    cat "$chunkprefix$currentchunk" && rm -f "$chunkprefix$currentchunk"
    currentchunk=$((currentchunk+1))
done | tar -xf -

คำปฏิเสธ

โปรดทราบว่าเพื่อให้การทำงานทั้งหมดเชลล์หางและตัดของคุณต้องจัดการกับจำนวนเต็ม 64- บิตอย่างถูกต้อง (คุณไม่จำเป็นต้องใช้คอมพิวเตอร์ 64 บิตหรือระบบปฏิบัติการสำหรับสิ่งนั้น) เหมืองแร่ไม่ แต่ถ้าคุณเรียกใช้สคริปต์ดังกล่าวข้างต้นในระบบโดยไม่ต้องการเหล่านี้คุณจะหลวมข้อมูลทั้งหมดใน archive.tar

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


0

หากคุณมีไฟล์วัตถุที่จะย้ายข้ามลองลอกมัน นี่จะเป็นการประหยัดพื้นที่จำนวนมาก

$ strip `find . -name "*.bin"`
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.