วิธีการส่งออก grep เป็น scp?


2

ฉันมีไฟล์โดยที่แต่ละบรรทัดเป็นชื่อไฟล์ เนื้อหาของไฟล์:

file1
file2
file3
...

ฉันเรียกใช้grepคำสั่งเพื่อรับชุดย่อยของรายการชื่อไฟล์

ฉันจะป้อนข้อมูลเอาต์พุตของgrepคำสั่งลงในได้scpอย่างไร? ฉันได้เล่นกับxargsและ $()ไม่ประสบความสำเร็จมาก ...

คำตอบ:


3

ไม่จำเป็นต้องใช้xargs:

for file in $(grep <some-pattern> <filelist>); do scp $file <remote>; done;

ที่ไหน

  • <some-pattern>เป็นgrepรูปแบบของคุณ
  • <filelist> เป็นรายการไฟล์ของคุณ
  • <remote>เป็นscpคำสั่งปลายทางระยะไกลของคุณ

forห่วงจะย้ำกว่าแต่ละบรรทัดผลิตโดยgrepผ่านนี้$fileซึ่งคุณสามารถกลับมาใช้ในคำสั่งดำเนินการระหว่างและdodone

โปรดดูเพิ่มเติมที่: คู่มือการใช้สคริปต์การทุบตีขั้นสูง: - ลูป


1
อย่าลืมอ้างชื่อไฟล์ของคุณ (ในกรณีที่มีช่องว่าง)
SamK

1
หากชื่อไฟล์ใด ๆ มีช่องว่างหรือตัวอักษรกลมมันจะไม่ทำงาน
Gilles

ตอนนี้สมมติว่ามีไฟล์หลายพันไฟล์ให้ค้นหา วิธีที่มีประสิทธิภาพคืออะไร?
StatsSorceress

@StatsSorceress เร็วกว่าgrepping ผ่านไฟล์หรือไม่ ไม่สามารถคิดอะไรได้เลย แต่คำตอบของ Gilles ดีกว่าในทุกกรณี
slhck

1

หากต้องการวนซ้ำชื่อรายการไฟล์ที่มีหนึ่งชื่อต่อบรรทัดคุณมีความเป็นไปได้หลายประการ:

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

    set -f; IFS='
    '
    scp -- $(…) remote.example.com:
    
  • ใช้readบิวด์อินเพื่อประมวลผลชื่อไฟล์ในลูป คุณต้องระวังอีกครั้งเพราะreadปฏิบัติกับเครื่องหมายแบ็กสแลชและ$IFSอักขระเป็นพิเศษ

    … | while IFS= read -r x; do scp -- "$x" remote.example.com: done
    
  • คุณสามารถใช้ GNU xargs ได้ แต่คุณต้องเหยียบอย่างระมัดระวังเพราะ xargs ต้องการอินพุตในรูปแบบที่ยกมาอย่างผิดปกติ คุณต้องผ่านการเลือกที่จะเลือกอย่างชัดเจนขึ้นบรรทัดใหม่เป็นตัวคั่นการป้อนข้อมูลและปิดพฤติกรรมพิเศษของช่องว่างและ-d '\n'\'"

    … | xargs -d '\n' -I {} scp {} remote.example.com:
    

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

    … | xargs -d '\n' sh -c 'scp -- "$@" "$0"' remote.example.com:
    
  • วิธีที่ง่ายกว่าในการใช้xargsคือรับรายการที่คั่นด้วย null แทนการขึ้นบรรทัดใหม่ สิ่งนี้ต้องการ-0ตัวเลือกซึ่งรองรับโดย GNU xargs และ * BSD ล่าสุด ดังที่กล่าวข้างต้นการผลักข้อโต้แย้งไปสู่ตำแหน่งที่ไม่ใช่ครั้งสุดท้ายนั้นจำเป็นต้องใช้งานสักหน่อย

    … | tr '\n' '\0' | xargs -0 sh -c 'scp -- "$@" "$0"' remote.example.com:
    

ส่วนหนึ่งจะเป็นgrep NAME_REGEXP /path/to/filenames.listถ้าคุณหมายถึงการกรองชื่อไฟล์ด้วยสีหน้าปกติ หากคุณต้องการกรองเนื้อหาไฟล์ให้ใช้หนึ่งในเทคนิคด้านบนเพื่อป้อนชื่อไฟล์grepเช่น

set -f; IFS='
'
scp -- $(grep -l CONTENT_REGEXP -- $(cat /path/to/filenames.list)) \
    remote.example.com:

ความเป็นไปได้อีกอย่างที่เลี่ยงผ่านปัญหาเชลล์คือการใช้rsyncและ--files-fromตัวเลือก สมมติว่าชื่อไฟล์นั้นสัมพันธ์กับไดเรกทอรีปัจจุบัน:

grep NAME_REGEXP /path/to/filenames.list |
rsync -a --files-from - . remote.example.com:

ฉันจะให้คุณอย่างนั้น! (เพียงแค่สงสัยไม่ที่ยังคงปรับ downvoting ถ้ามันทำงานให้กับสหกรณ์?)
slhck

@slhck คำตอบใด ๆ ที่ผิด (และฉันไม่ได้หมายถึงรายละเอียดที่ผิดถ้ามันเป็นเพียงเรื่องของการเพิ่มคำพูดหรือสองฉันจะแก้ไขคำตอบของคุณ) เป็นเป้าหมาย downvoting ที่ถูกต้องตามกฎหมายในความเป็นจริงมันควรลงคะแนน คำตอบที่ดูเหมาะสมเมื่อคุณทดสอบในตัวอย่างง่ายๆ แต่การหยุดพักในสถานการณ์จริงเป็นสิ่งที่เลวร้ายที่สุด
Gilles

ดี imo มันไม่ "ผิด" เมื่อมันทำงาน - แม้ว่ามันอาจเป็นสถานการณ์ง่าย ๆ ปุ่มจริงกล่าวว่า "คำตอบนี้ไม่เป็นประโยชน์" และมันก็เห็นได้ชัดว่าเป็นประโยชน์ ฉันรู้ว่ามันจะไม่ทำงานกับชื่อไฟล์ที่ซับซ้อนและโดยการเพิ่มความคิดเห็นของคุณด้านบนนั่นเป็นคำอธิบายที่ชัดเจน แต่ใช่เราปล่อยมันไว้อย่างนั้นไม่ไปสู้มัน!
slhck

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

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