วิธีใช้> ในคำสั่ง xargs


160

ฉันต้องการค้นหาคำสั่ง bash ที่จะให้ฉัน grep ทุกไฟล์ในไดเรกทอรีและเขียนผลลัพธ์ของ grep นั้นไปยังไฟล์แยกต่างหาก ฉันเดาว่าจะต้องทำอะไรแบบนี้

ls -1 | xargs -I{} "grep ABC '{}' > '{}'.out"

แต่เท่าที่ฉันรู้ xargs ไม่ชอบอัญประกาศ อย่างไรก็ตามหากฉันลบเครื่องหมายคำพูดคู่ออกคำสั่งจะเปลี่ยนทิศทางเอาต์พุตของคำสั่งทั้งหมดไปยังไฟล์เดียวที่เรียกว่า '{}' ออกแทนที่จะเป็นชุดไฟล์แต่ละไฟล์

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

คำตอบ:


201

อย่าทำผิดพลาดในการทำเช่นนี้:

sh -c "grep ABC {} > {}.out"

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

xargs -I{} sh -c 'grep ABC "$1" > "$1.out"' -- {}

นำไปใช้เช่นเดียวกับxargsfind

ยังไงก็ตามอย่าใช้ xargs โดยไม่มี-0ตัวเลือก (ยกเว้นการใช้งานแบบโต้ตอบครั้งเดียวที่หายากและควบคุมได้โดยที่คุณไม่ต้องกังวลเกี่ยวกับการทำลายข้อมูลของคุณ)

lsนอกจากนี้ยังทำไม่ได้แยก เคย. ใช้ globbing หรือfindแทน:http://mywiki.wooledge.org/ParsingLs

ใช้findสำหรับทุกสิ่งที่ต้องการเรียกซ้ำและวนรอบที่เรียบง่ายด้วยรูปวงกลมสำหรับทุกสิ่ง:

find /foo -exec sh -c 'grep "$1" > "$1.out"' -- {} \;

หรือไม่เรียกซ้ำ:

for file in *; do grep "$file" > "$file.out"; done

สังเกตการใช้คำพูดที่เหมาะสม


เพิ่มขึ้น แต่มีข้อสงสัย regd ไม่ได้ใช้xargsโดยไม่ต้อง-0: นี้ใช้เฉพาะเมื่อคุณท่อfindของการส่งออกด้วยxargsใช่มั้ย? เมื่อฉันxargs -a <input_file>จะใช้ฉันจะทำอย่างไร คำสั่งส่วนใหญ่เช่นgrepเอาท์พุทด้วย\nและไม่ใช่\0.วิธีเดียวที่ฉันสามารถนึกถึงtrการแก้ไขสิ่งนี้คือการใช้อีกครั้งเพื่อแก้ไขปัญหาที่อาจเกิดขึ้น แต่ทำไมมันถึงสำคัญที่จะใช้กับเท่านั้น-0?
legends2k

3
@ legends2k เพราะเมื่อคุณไม่ได้ใช้-0, xargsจะใช้ชื่อไฟล์ของคุณและทำลายทุกช่องว่างราคาและเครื่องหมายในพวกเขา คุณควรลืมxargsเป็นเครื่องมือ หากคุณมีเส้นใช้ bash loop เพื่อย้ำบรรทัด: while read line; do <command> "$REPLY"; done < file-with-linesหรือcommand | while ...
lhunath

1
ว้าวไม่รู้เรื่องนั้นขอบคุณสำหรับรายละเอียด! ดังนั้นเพื่อความสะดวกในการพกพา (เนื่องจากไม่ใช่ทั้งหมดxargsของ GNU) จึงxargsจำเป็นต้องหลีกเลี่ยงหากไม่มีใครสามารถใช้กับมัน-0ได้ ขอบคุณ.
legends2k

1
แม้ว่าฉันจะขอบคุณคำอธิบายโดยละเอียดสำหรับกรณีการใช้งานเฉพาะนี้ แต่คำถามเกี่ยวกับการเปลี่ยนเส้นทางของผลลัพธ์xargsซึ่งไม่ได้เกี่ยวข้องกับการแยกวิเคราะห์lsหรือการใช้งานsh -cเสมอไป สิ่งนี้ไม่ได้ตอบคำถามเพียงเล็กน้อย แต่เป็นผลการค้นหา google ครั้งแรกสำหรับคำถามเพียงเพิ่มความสับสน
pandasauce

1
@Ihunath สวัสดีคำตอบของคุณใช้ได้ดีสำหรับฉัน แต่คุณสามารถให้บางคำอธิบายรายละเอียดเกี่ยวกับการเชื่อมโยงหรือxargs -I{} sh -c 'grep ABC "$1" > "$1.out"' -- {}? โดยเฉพาะอย่างยิ่งกฎของเครื่องหมายคำพูด (คู่) ที่ฝังอยู่และสัญลักษณ์ "-" ในตอนท้าย ขอบคุณ
Scott Yang

40

วิธีการแก้ปัญหาที่ไม่มีxargsดังต่อไปนี้:

find . -mindepth 1 -maxdepth 1 -type f -exec sh -c "grep ABC '{}' > '{}.out'" \;

... และสิ่งเดียวกันสามารถทำได้ด้วย xargsมันกลับกลายเป็น:

ls -1 | xargs -I {} sh -c "grep ABC '{}' > '{}.out'"

แก้ไข : ราคาเดียวเพิ่มเข้ามาหลังจากคำพูดโดยlhunath


เขาบอกว่าเขาต้องการใช้ xargs ฉันโพสต์วิธีการแก้ปัญหาโดยไม่มีมัน แต่ลบเมื่อฉันเห็นว่าเขาต้องการ xargs
Zifre

คุณถูก. เหตุผลที่ฉันโพสต์คำตอบของฉันคือการมีวิธีแก้ไขปัญหาทางเลือกเพื่อให้งานดีกว่าไม่มีเลย ปรากฎว่ามันทำให้ฉันในการติดตามที่ถูกต้องเพื่อค้นหาคำตอบที่ต้องการ (นั่นคือเคล็ดลับ sh -c)
Stephan202

14

ฉันถือว่าตัวอย่างของคุณเป็นเพียงตัวอย่างและคุณอาจต้องการ> เพื่อสิ่งอื่น GNU Parallel http://www.gnu.org/software/parallel/อาจช่วยคุณได้ ไม่จำเป็นต้องมีการอ้างอิงเพิ่มเติมตราบใดที่ชื่อไฟล์ของคุณไม่มี \ n:

ls | parallel "grep ABC {} > {}.out"

หากคุณมีชื่อไฟล์โดย \ n อยู่:

find . -print0 | parallel -0 "grep ABC {} > {}.out"

ในฐานะโบนัสที่เพิ่มเข้ามาคุณจะได้งานที่ขนานกัน

ดูวิดีโอแนะนำเพื่อเรียนรู้เพิ่มเติม: http://pi.dk/1

การติดตั้ง 10 วินาทีจะพยายามทำการติดตั้งแบบเต็ม หากล้มเหลวการติดตั้งส่วนบุคคล; หากล้มเหลวการติดตั้งเพียงเล็กน้อย:

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 3374ec53bacb199b245af2dda86df6c9
12345678 3374ec53 bacb199b 245af2dd a86df6c9
$ md5sum install.sh | grep 029a9ac06e8b5bc6052eac57b2c3c9ca
029a9ac0 6e8b5bc6 052eac57 b2c3c9ca
$ sha512sum install.sh | grep f517006d9897747bed8a4694b1acba1b
40f53af6 9e20dae5 713ba06c f517006d 9897747b ed8a4694 b1acba1b 1464beb4
60055629 3f2356f3 3e9c4e3c 76e3f3af a9db4b32 bd33322b 975696fc e6b23cfb
$ bash install.sh

หากคุณต้องการที่จะย้ายไปยังเซิร์ฟเวอร์ที่ไม่ได้มี GNU parallel --embedขนานติดตั้งลอง

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