dd: ไฟล์อินพุตหลายไฟล์


14

ฉันต้องต่อชิ้นไฟล์สองไฟล์เข้าด้วยกัน:

ถ้าฉันต้องการเชื่อมไฟล์ทั้งหมดเข้าด้วยกันฉันก็ทำได้

cat file1 file2 > output

แต่ฉันต้องข้าม 1MB แรกจากไฟล์แรกและฉันต้องการเพียง 10 MB จากไฟล์ที่สอง ddเสียงเหมือนงานสำหรับ

dd if=file1 bs=1M count=99 skip=1 of=temp1
dd if=file2 bs=1M count=10 of=temp2
cat temp1 temp2 > final_output

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

คำตอบ:


21

dd สามารถเขียนถึง stdout ได้เช่นกัน

( dd if=file1 bs=1M count=99 skip=1
  dd if=file2 bs=1M count=10  ) > final_output

นี่อาจเป็นวิธีที่ดีที่สุด ไฟล์เอาต์พุตไม่ได้ปิด / เปิดใหม่ (เหมือนเดิมoflag=append conv=notrunc) ดังนั้นระบบไฟล์ที่ทำการจัดสรรล่าช้า (เช่น XFS) มีโอกาสน้อยที่สุดที่จะตัดสินใจว่าไฟล์จะถูกเขียนเมื่อยังเหลืออยู่
Peter Cordes

@PeterCordes นั้นเป็นจุดที่ดี แต่ตราบใดที่ddยังไม่ได้รับการร้องขอการsyncจัดสรรที่ล่าช้าก็ไม่ควรเริ่มทันที
Stephen Kitt

@StephenKitt: คุณพูดถูก ฉันคิดว่าการจัดสรรล่วงหน้าของ XFS ซึ่งมันจำเป็นต้องตรวจสอบรูปแบบการเข้าถึงแบบปิด / เปิดใหม่ (บางครั้งเห็นเป็นไฟล์บันทึก)
Peter Cordes

3
ในเชลล์ที่ชอบbashและmkshไม่ได้ปรับส้อมให้เหมาะสมสำหรับคำสั่งสุดท้ายในเชลล์ย่อยคุณสามารถทำให้มีประสิทธิภาพมากขึ้นเล็กน้อยโดยการแทนที่เชลล์ย่อยด้วยกลุ่มคำสั่ง สำหรับเชลล์อื่นมันไม่สำคัญและวิธีการ subshell อาจมีประสิทธิภาพมากกว่าเล็กน้อยเนื่องจากเชลล์ไม่จำเป็นต้องบันทึกและกู้คืน stdout
Stéphane Chazelas

10

ฉันไม่คิดว่าคุณสามารถอ่านไฟล์หลาย ๆ ไฟล์ได้อย่างง่ายดายในการddเรียกใช้ครั้งเดียวแต่คุณสามารถต่อท้ายเพื่อสร้างไฟล์เอาต์พุตในหลายขั้นตอน:

dd if=file1 bs=1M count=99 skip=1 of=final_output
dd if=file2 bs=1M count=10 of=final_output oflag=append conv=notrunc

คุณต้องระบุทั้งสองและconv=notrunc oflag=appendครั้งแรกหลีกเลี่ยงการตัดทอนผลลัพธ์ที่สองเริ่มเขียนจากจุดสิ้นสุดของไฟล์ที่มีอยู่


8

จำไว้ว่าddเป็นอินเตอร์เฟซดิบไปread(), write()และlseek()ระบบโทร คุณสามารถใช้มันได้อย่างน่าเชื่อถือเพื่อแยกส่วนของข้อมูลออกจากไฟล์ปกติอุปกรณ์บล็อกและอุปกรณ์ตัวอักษร (เช่น/dev/urandom) ซึ่งเป็นไฟล์ที่read(buf, size)รับประกันว่าจะส่งคืนsizeตราบใดที่ไม่ถึงจุดสิ้นสุดของไฟล์

สำหรับท่อซ็อกเก็ตและอุปกรณ์ตัวอักษรมากที่สุด (เช่น ttys) คุณมีการรับประกันดังกล่าวไม่จนกว่าคุณจะทำread()ของขนาด 1 หรือใช้ GNU นามสกุลddiflag=fullblock

ดังนั้นทั้ง:

{
  gdd < file1 bs=1M iflag=fullblock count=99 skip=1
  gdd < file2 bs=1M iflag=fullblock count=10
} > final_output

หรือ:

M=1048576
{
  dd < file1 bs=1 count="$((99*M))" skip="$M"
  dd < file2 bs=1 count="$((10*M))"
} > final_output

หรือกับกระสุนที่มี builtin รองรับผู้ใช้งานเช่นksh93:

M=1048576
{
  command /opt/ast/bin/head -c "$((99*M))" < file1 <#((M))
  command /opt/ast/bin/head -c "$((10*M))" < file2
}

หรือzsh(สมมติว่าคุณheadสนับสนุน-cตัวเลือกที่นี่):

zmodload zsh/system &&
{
  sysseek 1048576 && head -c 99M &&
  head -c 10M < file2
} < file1 > final_output

คุณต้องการคำพูดจริง ๆ หรือไม่? ผลลัพธ์จะเป็นจำนวนเต็มเสมอหรือไม่?
Steven Penny

@StevenPenny การออกจากส่วนขยายที่ไม่ได้กล่าวถึงคือการขอให้เชลล์แยก + glob ซึ่งจะไม่มีเหตุผลใด ๆ $IFSส่วนที่แยกถูกทำในมูลค่าปัจจุบันของ นั่นคือไม่คำนึงถึงเนื้อหาของตัวแปร / การขยายตัว ดูเพิ่มเติมที่นัยยะด้านความปลอดภัยของการลืมอ้างตัวแปรใน bash / POSIX shells
Stéphane Chazelas

@ Stéphane Chazelas - ในตัวอย่างแรกคุณจะใช้แทนgdd ddนั่นคือการพิมพ์ผิดหรือเป็นความตั้งใจที่?
Martin Vegter

3

ด้วยbash ismและ function "ใช้ประโยชน์ของcat " ที่ไม่มีประโยชน์แต่ใกล้เคียงกับไวยากรณ์ที่ OP ใช้:

cat <(dd if=file1 bs=1M count=99 skip=1) \
    <(dd if=file2 bs=1M count=10) \
   > final_output

(ที่ถูกกล่าวว่าคำตอบของ Stephen Kitt น่าจะเป็นวิธีที่มีประสิทธิภาพมากที่สุด)


3
พูดอย่างเคร่งครัด<(...)เป็นkshismซึ่งทั้งสองzshและbashคัดลอก
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.