ฉันจะใช้ xargs เพื่อคัดลอกไฟล์ที่มีช่องว่างและเครื่องหมายคำพูดในชื่อได้อย่างไร


232

ฉันพยายามคัดลอกไฟล์หลายไฟล์ด้านล่างไดเรกทอรีและไฟล์จำนวนหนึ่งมีช่องว่างและเครื่องหมายคำพูดเดี่ยวในชื่อของพวกเขา เมื่อฉันพยายามสตริงด้วยกันfindและgrepด้วยxargsฉันได้รับข้อผิดพลาดต่อไปนี้:

find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar
xargs: unterminated quote

คำแนะนำใด ๆ สำหรับการใช้งาน xargs ที่มีประสิทธิภาพยิ่งขึ้น

นี้คือบนMac OS X 10.5.3 (Leopard) กับ xargsBSD


2
ข้อความแสดงข้อผิดพลาดของ GNU xargs สำหรับสิ่งนี้ด้วยชื่อไฟล์ที่มีเครื่องหมายคำพูดเดียวมีประโยชน์มากกว่า: "xargs: อัญประกาศเดี่ยวที่ไม่ตรงกัน;
Steve Jessop

3
GNU xargs มี--delimiterตัวเลือก ( -d) ลองด้วย\nตัวคั่นซึ่งจะป้องกันไม่ให้xargsแยกบรรทัดด้วยช่องว่างเป็นหลายคำ / อาร์กิวเมนต์
MattBianco

คำตอบ:


199

คุณสามารถรวมทั้งหมดนั้นไว้ในfindคำสั่งเดียว:

find . -iname "*foobar*" -exec cp -- "{}" ~/foo/bar \;

วิธีนี้จะจัดการชื่อไฟล์และไดเรกทอรีที่มีช่องว่าง คุณสามารถใช้-nameเพื่อรับผลลัพธ์เป็นกรณี ๆ ไป

หมายเหตุ: การ--ตั้งค่าสถานะผ่านเพื่อcpป้องกันไม่ให้ประมวลผลไฟล์ที่เริ่มต้นด้วย-ตัวเลือก


70
ผู้คนใช้ xargs เพราะปกติแล้วมันจะเร็วกว่าในการเรียกใช้ executable 5 ครั้งโดยมีอาร์กิวเมนต์ 200 ครั้งในแต่ละครั้งแทนที่จะเรียกว่า 1,000 ครั้งโดยมีหนึ่งอาร์กิวเมนต์ทุกครั้ง
tzot

12
คำตอบจาก Chris Jester-Young ควรเป็น "คำตอบที่ดี" ที่นั่น ... BTW โซลูชันนี้ใช้ไม่ได้หากชื่อไฟล์ขึ้นต้นด้วย "-" อย่างน้อยมันต้องการ "-" หลังจาก cp
Keltia

11
ตัวอย่างความเร็ว - มากกว่า 829 ไฟล์วิธี "find -exec" ใช้เวลา 26 วินาทีในขณะที่เครื่องมือวิธี "find -print0 | xargs --null" 0.7 วินาที ความแตกต่างที่สำคัญ
Peter Porter

7
@tzot ความคิดเห็นที่ล่าช้า แต่xargsไม่จำเป็นต้องระบุถึงปัญหาที่คุณอธิบายและfindสนับสนุน-exec +เครื่องหมายวรรคตอนแล้ว
jlliagre

3
ไม่ตอบคำถามว่าจะจัดการกับช่องว่างได้อย่างไร
Ben Glasser

117

find . -print0 | grep --null 'FooBar' | xargs -0 ...

ฉันไม่รู้ว่าgrepสนับสนุน--nullหรือxargsสนับสนุน-0บน Leopard แต่ใน GNU ทุกอย่างดี


1
Leopard รองรับ "-Z" (เป็น grep GNU) และแน่นอนค้นหา (1) และ xargs (1) รองรับ "-0"
Keltia

1
บน OS X 10.9 grep -{z|Z}หมายถึง "ประพฤติเป็น zgrep" (คลายการบีบอัด) และไม่ใช่ "การพิมพ์ไบต์ศูนย์หลังจากแต่ละชื่อไฟล์" ใช้grep --nullเพื่อให้บรรลุหลัง
bassim

4
มีอะไรผิดปกติกับfind . -name 'FooBar' -print0 | xargs -0 ...?
Quentin Pradet

1
@QuentinPradet แน่นอนสำหรับสตริงคงที่เช่น "FooBar" -nameหรือ-pathทำงานได้ดี OP ระบุการใช้grepอย่างน่าจะเป็นเพราะพวกเขาต้องการกรองรายการโดยใช้นิพจน์ทั่วไป
Chris Jester-Young

1
@ Hi-แองเจิลที่ว่าทำไมผมใช้ร่วมกับxargs -0 find -print0หลังพิมพ์ชื่อไฟล์ด้วย NUL terminator และอดีตรับไฟล์ด้วยวิธีนี้ ทำไม? ชื่อไฟล์ใน Unix สามารถมีอักขระขึ้นบรรทัดใหม่ แต่จะต้องไม่มีอักขระ NUL
Chris Jester-Young

92

วิธีที่ง่ายที่สุดในการทำสิ่งที่ผู้ลงประกาศดั้งเดิมต้องการคือการเปลี่ยนตัวคั่นจากช่องว่างใด ๆ เป็นเพียงตัวอักษรสุดท้ายของบรรทัดดังนี้:

find whatever ... | xargs -d "\n" cp -t /var/tmp

4
Anwser นี้ง่ายมีประสิทธิภาพและตรงประเด็น: ตัวคั่นเริ่มต้นที่กำหนดไว้สำหรับ xargs นั้นกว้างเกินไปและจำเป็นต้องแคบลงสำหรับสิ่งที่ OP ต้องการทำ ฉันรู้ว่ามือแรกนี้เพราะฉันพบปัญหาเดียวกันนี้วันนี้ทำสิ่งที่คล้ายกันยกเว้นใน cygwin หากฉันอ่านวิธีใช้สำหรับคำสั่ง xargs ฉันอาจหลีกเลี่ยงอาการปวดหัวเล็กน้อย แต่โซลูชันของคุณจะแก้ไขปัญหาให้ฉัน ขอบคุณมาก! (ใช่ OP อยู่ใน MacOS โดยใช้ BSD xargs ซึ่งฉันไม่ได้ใช้ แต่ฉันหวังว่าพารามิเตอร์ xargs "-d" จะมีอยู่ในทุกรุ่น)
Etienne Delavennat

7
คำตอบที่ดี แต่ไม่ได้ทำงานบน Mac แต่เราสามารถท่อหาเข้าไปใน sed -e 's_\(.*\)_"\1"_g'คำพูดแรงไปรอบ ๆ ชื่อไฟล์
ishahak

10
นี่ควรเป็นคำตอบที่ยอมรับได้ xargsคำถามคือเกี่ยวกับการใช้
Mohammad Alhashash

2
ฉันได้รับxargs: illegal option -- d
nehem

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

71

สิ่งนี้มีประสิทธิภาพมากกว่าเนื่องจากไม่ได้รัน "cp" หลายครั้ง:

find -name '*FooBar*' -print0 | xargs -0 cp -t ~/foo/bar

1
สิ่งนี้ไม่ได้ผลสำหรับฉัน มันพยายามที่จะ cp ~ / foo / bar ในสิ่งที่คุณค้นหา แต่ไม่ใช่สิ่งที่ตรงกันข้าม
Shervin Asgari

13
แฟล็ก -t เป็น cp เป็นส่วนขยาย GNU, AFAIK และไม่พร้อมใช้งานใน OS X แต่ถ้าเป็นเช่นนั้นมันจะทำงานตามที่แสดงในคำตอบนี้
metamatt

2
ฉันใช้ลีนุกซ์ ขอบคุณสำหรับสวิตช์ '-t' นั่นคือสิ่งที่ฉันหายไป :-)
Vahid Pazirandeh

59

ฉันพบปัญหาเดียวกัน นี่คือวิธีที่ฉันแก้ไขมัน:

find . -name '*FoooBar*' | sed 's/.*/"&"/' | xargs cp ~/foo/bar

ฉันใช้sedแทนอินพุตแต่ละบรรทัดด้วยบรรทัดเดียวกัน แต่ล้อมรอบด้วยเครื่องหมายคำพูดคู่ จากsedหน้าคน " ... เครื่องหมายและ (` `& '') ที่ปรากฏในการแทนที่จะถูกแทนที่ด้วยสตริงที่ตรงกับ RE ... " - ในกรณีนี้.*ทั้งบรรทัด

วิธีนี้จะช่วยแก้ไขxargs: unterminated quoteข้อผิดพลาด


3
ฉันอยู่บน windows และใช้ gnuwin32 ดังนั้นฉันต้องใช้sed s/.*/\"&\"/เพื่อให้มันใช้งานได้
Pat

ใช่ แต่สมมุติว่านี่จะไม่จัดการชื่อไฟล์ด้วย"ใน - เว้นแต่ว่า sed จะเสนอราคาด้วย?
artfulrobot

การใช้sedอัจฉริยะและตอนนี้ทางออกที่ถูกต้องโดยไม่ต้องเขียนปัญหาใหม่!
entonio

53

วิธีนี้ใช้ได้กับMac OS X v10.7.5 (Lion):

find . | grep FooBar | xargs -I{} cp {} ~/foo/bar

ฉันยังทดสอบไวยากรณ์ที่แน่นอนที่คุณโพสต์ ที่ยังทำงานได้ดีใน 10.7.5


4
ใช้งานได้ แต่-Iบอกเป็นนัย-L 1(เช่นบอกด้วยตนเอง) ซึ่งหมายความว่าคำสั่ง cp จะถูกเรียกใช้หนึ่งครั้งต่อไฟล์ = v ช้า
artfulrobot

xargs -J% cp% <ปลายทาง dir> อาจมีประสิทธิภาพมากกว่าบน OSX
วอล์คเกอร์ D

3
ขออภัย แต่นี่ผิด ก่อนอื่นมันก่อให้เกิดข้อผิดพลาดอย่างแท้จริงที่ TO ต้องการหลีกเลี่ยง คุณต้องใช้find ... -print0และxargs -0ทำงาน arround xargs ของ "โดยราคาเริ่มต้นเป็นพิเศษ" ประการที่สองโดยทั่วไปจะ'{}'ไม่ใช้{}คำสั่งที่ส่งไปยัง xargs เพื่อป้องกันช่องว่างและอักขระพิเศษ
Andreas Spindler

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

12

xargsก็ไม่ได้ใช้ มันเป็นโปรแกรมที่เนี้ยบ แต่มันไม่เข้ากันได้ดีfindเมื่อต้องเผชิญกับคดีที่ไม่สำคัญ

นี่คือแบบพกพา (POSIX) วิธีการแก้ปัญหาคือหนึ่งที่ไม่ต้องใช้find, xargsหรือcpนามสกุลเฉพาะ GNU:

find . -name "*FooBar*" -exec sh -c 'cp -- "$@" ~/foo/bar' sh {} +

หมายเหตุสิ้นสุดแทนปกติมากขึ้น+;

วิธีนี้:

  • จัดการไฟล์และไดเรกทอรีอย่างถูกต้องด้วยช่องว่างที่ฝังตัวบรรทัดใหม่หรืออักขระแปลกใหม่

  • ทำงานบนระบบ Unix และ Linux ใด ๆ แม้จะไม่ได้ให้ชุดเครื่องมือ GNU

  • ไม่ได้ใช้xargsซึ่งเป็นโปรแกรมที่ดีและมีประโยชน์ แต่ต้องมีการปรับแต่งและคุณสมบัติที่ไม่ได้มาตรฐานมากเกินไปในการจัดการfindเอาต์พุตอย่างถูกต้อง

  • ก็มีประสิทธิภาพมากกว่า (อ่านเร็วกว่า) มากกว่าคำตอบที่ยอมรับและส่วนใหญ่ถ้าไม่ใช่คำตอบอื่นทั้งหมด

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



1
@PeterMortensen คุณอาจมองข้ามจุดสิ้นสุดบวก findสามารถทำสิ่งที่xargsทำโดยไม่มีค่าใช้จ่ายใด ๆ
jlliagre


8

สำหรับผู้ที่ต้องใช้คำสั่งนอกเหนือจากการค้นหาเช่นls:

find . | grep "FooBar" | tr \\n \\0 | xargs -0 -I{} cp "{}" ~/foo/bar

1
ใช้งานได้ แต่ช้าเพราะ-Iบอกเป็นนัย-L 1
artfulrobot

6
find | perl -lne 'print quotemeta' | xargs ls -d

ฉันเชื่อว่าสิ่งนี้จะทำงานได้อย่างน่าเชื่อถือสำหรับตัวละครใด ๆ ยกเว้น line-feed (และฉันสงสัยว่าถ้าคุณมี line-feed ในชื่อไฟล์ของคุณแสดงว่าคุณมีปัญหาที่เลวร้ายยิ่งกว่านี้) ไม่จำเป็นต้องใช้ GNU findutils เพียง Perl ดังนั้นมันควรทำงานได้ทุกที่


เป็นไปได้หรือไม่ที่จะมีการป้อนบรรทัดในชื่อไฟล์? ไม่เคยได้ยินเรื่องนี้
mtk

2
แน่นอนมันคือ ลองเช่นmkdir test && cd test && perl -e 'open $fh, ">", "this-file-contains-a-\n-here"' && ls | od -tx1
mavit

1
|perl -lne 'print quotemeta'เป็นสิ่งที่ฉันกำลังมองหา โพสต์อื่น ๆ ที่นี่ไม่ได้ช่วยฉันเพราะfindฉันต้องการใช้grep -rlเพื่อลดจำนวนไฟล์ PHP ให้เหลือเพียงไฟล์ที่ติดมัลแวร์
Marcos

perl และ quotemeta นั้นกว้างกว่า print0 / -0 - ขอบคุณสำหรับโซลูชันทั่วไปในการ pipelining ไฟล์ที่มีช่องว่าง
bmike

5

ฉันพบว่าไวยากรณ์ต่อไปนี้ใช้งานได้ดีสำหรับฉัน

find /usr/pcapps/ -mount -type f -size +1000000c | perl -lpe ' s{ }{\\ }g ' | xargs ls -l | sort +4nr | head -200

ในตัวอย่างนี้ฉันกำลังมองหาไฟล์ที่ใหญ่ที่สุด 200 ไฟล์มากกว่า 1,000,000 ไบต์ในระบบไฟล์ที่ติดตั้งที่ "/ usr / pcapps"

สายการบิน Perl ระหว่าง "ค้นหา" และ "xargs" หนี / อ้างอิงแต่ละช่องว่างเพื่อให้ "xargs" ผ่านชื่อไฟล์ใด ๆ ที่มีช่องว่างที่ฝังตัวเพื่อ "ls" เป็นอาร์กิวเมนต์เดียว


3

Frame challenge - คุณกำลังถามวิธีใช้ xargs คำตอบคือ: คุณไม่ได้ใช้ xargs เพราะคุณไม่ต้องการมัน

ความคิดเห็นโดยuser80168อธิบายถึงวิธีการที่จะทำเช่นนี้โดยตรงกับซีพีโดยไม่ต้องโทร CP สำหรับทุกไฟล์:

find . -name '*FooBar*' -exec cp -t /tmp -- {} +

งานนี้เพราะ:

  • cp -tธงช่วยให้การให้ไดเรกทอรีเป้าหมายที่อยู่ใกล้จุดเริ่มต้นของcpมากกว่าใกล้จะจบ จากman cp:
   -t, --target-directory=DIRECTORY
         copy all SOURCE arguments into DIRECTORY
  • --ธงบอกcpจะตีความทุกอย่างหลังจากเป็นชื่อไฟล์ไม่ธงดังนั้นไฟล์ที่เริ่มต้นด้วย-หรือ--ไม่สับสนcp; คุณยังต้องใช้สิ่งนี้เนื่องจาก-/ --อักขระถูกตีความโดยcpในขณะที่อักขระพิเศษอื่น ๆ ถูกตีความโดยเชลล์

  • find -exec command {} +ตัวแปรหลักไม่เช่นเดียวกับ xargs จากman find:

   -exec command {} +                                                     
         This  variant  of the -exec action runs the specified command on
         the selected files, but the command line is built  by  appending
         each  selected file name at the end; the total number of invoca‐
         matched  files.   The command line is built in much the same way
         that xargs builds its command lines.  Only one instance of  `{}'
         is  allowed  within the command, and (when find is being invoked
         from a shell) it should be quoted (for example, '{}') to protect
         it  from  interpretation  by shells.  The command is executed in
         the starting directory.  If any invocation  returns  a  non-zero
         value  as exit status, then find returns a non-zero exit status.
         If find encounters an error, this can sometimes cause an immedi‐
         ate  exit, so some pending commands may not be run at all.  This
         variant of -exec always returns true.

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


การค้นหาที่น่าตื่นตาตื่นใจฉันไม่มีความคิด !!! "-exec utility [อาร์กิวเมนต์ ... ] {} + เหมือนกับ -exec ยกเว้นว่า` `{} '' จะถูกแทนที่ด้วยชื่อพา ธ จำนวนมากที่สุดเท่าที่จะเป็นไปได้สำหรับการเรียกใช้ยูทิลิตี้แต่ละครั้งลักษณะการทำงานนี้คล้ายกับของ xargs (1 )." ในการใช้ BSD
Conny

2

โปรดทราบว่าตัวเลือกส่วนใหญ่ที่กล่าวถึงในคำตอบอื่น ๆ ไม่ใช่มาตรฐานบนแพลตฟอร์มที่ไม่ได้ใช้อรรถประโยชน์ของ GNU (เช่น Solaris, AIX, HP-UX เป็นต้น) ดูPOSIXข้อมูลจำเพาะสำหรับพฤติกรรม xargs 'มาตรฐาน'

ฉันยังพบพฤติกรรมของ xargs โดยที่มันรันคำสั่งอย่างน้อยหนึ่งครั้งแม้ไม่มีอินพุตเพื่อสร้างความรำคาญ

ฉันเขียน xargs (xargl) เวอร์ชั่นส่วนตัวของตัวเองเพื่อจัดการกับปัญหาช่องว่างในชื่อ (เฉพาะการขึ้นบรรทัดใหม่ - แม้ว่า 'find ... -print0' และ 'xargs -0' นั้นค่อนข้างเรียบร้อยเพราะชื่อไฟล์ไม่สามารถทำได้ มีอักขระ ASCII NUL '\ 0' xargl ของฉันยังไม่สมบูรณ์เท่าที่ควรจะเป็นการเผยแพร่ที่คุ้มค่าโดยเฉพาะอย่างยิ่งเนื่องจาก GNU มีสิ่งอำนวยความสะดวกที่ดีอย่างน้อย


2
GitHub หรือไม่เกิดขึ้น
Corey Goldberg

@CoreyGoldberg: ฉันคิดว่ามันไม่ได้เกิดขึ้นแล้ว
Jonathan Leffler

POSIX findไม่ต้องการxargsในตอนแรก (และนั่นก็เป็นจริงเมื่อ 11 ปีที่แล้ว)
jlliagre

2

ด้วย Bash (ไม่ใช่ POSIX) คุณสามารถใช้การทดแทนกระบวนการเพื่อรับบรรทัดปัจจุบันภายในตัวแปร สิ่งนี้ทำให้คุณสามารถใช้เครื่องหมายคำพูดเพื่อหลีกเลี่ยงอักขระพิเศษ:

while read line ; do cp "$line" ~/bar ; done < <(find . | grep foo)

2

สำหรับฉันฉันพยายามทำสิ่งที่แตกต่างออกไปเล็กน้อย ฉันต้องการคัดลอกไฟล์. txt ไปยังโฟลเดอร์ tmp ของฉัน ชื่อไฟล์. txt มีช่องว่างและเครื่องหมายวรรคตอน สิ่งนี้ใช้ได้กับ Mac ของฉัน

$ find . -type f -name '*.txt' | sed 's/'"'"'/\'"'"'/g' | sed 's/.*/"&"/'  | xargs -I{} cp -v {} ./tmp/

1

หากเวอร์ชัน find และ xarg บนระบบของคุณไม่รองรับ-print0และ-0สวิตช์ (ตัวอย่างเช่น AIX find และ xargs) คุณสามารถใช้โค้ดค้นหาที่น่ากลัวนี้:

 find . -name "*foo*" | sed -e "s/'/\\\'/g" -e 's/"/\\"/g' -e 's/ /\\ /g' | xargs cp /your/dest

ที่นี่จะคอยดูแลช่องว่างและคำพูดสำหรับ xargs

ทดสอบบน AIX 5.3


1

ฉันสร้างสคริปต์ตัวห่อแบบพกพาขนาดเล็กที่เรียกว่า "xargsL" รอบ ๆ "xargs" ซึ่งจัดการปัญหาส่วนใหญ่ได้

ตรงกันข้ามกับ xargs, xargsL ยอมรับชื่อพา ธ หนึ่งรายการต่อบรรทัด ชื่อพา ธ อาจมีอักขระใด ๆ ยกเว้น newline หรือ NUL ไบต์

ไม่มีการอนุญาตหรือการอ้างอิงในรายการไฟล์ - ชื่อไฟล์ของคุณอาจมีช่องว่างทุกประเภท, แบ็กสแลช, backticks, ตัวละครเชลล์คาร์ดและอักขระตัวแทนอื่น ๆ ที่คล้ายกัน - xargsL จะประมวลผลเป็นอักขระตามตัวอักษร

ในฐานะที่เป็นคุณสมบัติโบนัสเพิ่ม xargsL จะไม่เรียกใช้คำสั่งอีกครั้งหากไม่มีอินพุต!

บันทึกความแตกต่าง:

$ true | xargs echo no data
no data

$ true | xargsL echo no data # No output

อาร์กิวเมนต์ใด ๆ ที่กำหนดให้ xargsL จะถูกส่งผ่านไปยัง xargs

นี่คือสคริปต์เชลล์ "xargsL" POSIX:

#! /bin/sh
# Line-based version of "xargs" (one pathname per line which may contain any
# amount of whitespace except for newlines) with the added bonus feature that
# it will not execute the command if the input file is empty.
#
# Version 2018.76.3
#
# Copyright (c) 2018 Guenther Brunthaler. All rights reserved.
#
# This script is free software.
# Distribution is permitted under the terms of the GPLv3.

set -e
trap 'test $? = 0 || echo "$0 failed!" >& 2' 0

if IFS= read -r first
then
        {
                printf '%s\n' "$first"
                cat
        } | sed 's/./\\&/g' | xargs ${1+"$@"}
fi

ใส่สคริปต์ลงในไดเรกทอรีใน $ PATH ของคุณและอย่าลืม

$ chmod +x xargsL

สคริปต์ที่นั่นเพื่อให้สามารถเรียกใช้งานได้


1

รุ่น Perl ของ bill_starrจะทำงานได้ไม่ดีสำหรับการขึ้นบรรทัดใหม่ (เฉพาะ copes ที่มีช่องว่าง) สำหรับผู้ที่อยู่บนโซลาริสที่คุณไม่มีเครื่องมือ GNU รุ่นที่สมบูรณ์กว่านี้อาจเป็น (ใช้ sed) ...

find -type f | sed 's/./\\&/g' | xargs grep string_to_find

ปรับอาร์กิวเมนต์ find และ grep หรือคำสั่งอื่น ๆ ตามที่คุณต้องการ แต่ sed จะแก้ไขบรรทัด / ช่องว่าง / แท็บขึ้นบรรทัดใหม่ของคุณ


1

ฉันใช้คำตอบของ Bill Starแก้ไขเล็กน้อยใน Solaris:

find . -mtime +2 | perl -pe 's{^}{\"};s{$}{\"}' > ~/output.file

สิ่งนี้จะใส่เครื่องหมายคำพูดรอบแต่ละบรรทัด ฉันไม่ได้ใช้ตัวเลือก '-l' แม้ว่ามันอาจจะช่วยได้

รายการไฟล์ที่ฉันไปอาจมี '-' แต่ไม่ขึ้นบรรทัดใหม่ ฉันไม่ได้ใช้ไฟล์เอาต์พุตกับคำสั่งอื่น ๆ เพราะฉันต้องการตรวจสอบสิ่งที่พบก่อนที่ฉันจะเริ่มต้นลบพวกเขาอย่างหนาแน่นผ่านทาง xargs


1

ฉันเล่นกับสิ่งนี้เล็กน้อยเริ่มคิดปรับเปลี่ยน xargs และตระหนักว่าสำหรับกรณีการใช้งานประเภทที่เรากำลังพูดถึงที่นี่การปรับใช้อย่างง่ายใน Python เป็นแนวคิดที่ดีกว่า

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

ดูhttps://github.com/johnallsup/jda-misc-scripts/blob/master/yargsและhttps://github.com/johnallsup/jda-misc-scripts/blob/master/zargs.py

ด้วย yargs ตามที่เขียน (และติดตั้ง Python 3) คุณสามารถพิมพ์:

find .|grep "FooBar"|yargs -l 203 cp --after ~/foo/bar

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

หากคุณต้องการบางสิ่งที่เร็วขึ้นและไม่จำเป็นต้องใช้ Python ให้ใช้ zargs และ yargs เป็นแบบตัวอย่างและเขียนใหม่ใน C ++ หรือ C



-1

หากคุณกำลังใช้ Bash คุณสามารถแปลงstdoutเป็นอาร์เรย์ของเส้นโดยmapfile:

find . | grep "FooBar" | (mapfile -t; cp "${MAPFILE[@]}" ~/foobar)

ประโยชน์คือ:

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

    find . -name '*FooBar*' -exec cp -t ~/foobar -- {} +
    

    อย่างไรก็ตามคำสั่งบางอย่างไม่มีคุณสมบัติดังกล่าว

ข้อเสีย:

  • อาจจะไม่ใหญ่ถ้ามีชื่อไฟล์มากเกินไป (ขีด จำกัด หรือไม่ฉันไม่รู้ แต่ฉันได้ทดสอบกับไฟล์รายการ 10 MB ซึ่งมีชื่อไฟล์มากกว่า 10,000 ชื่อโดยไม่มีปัญหาภายใต้ Debian)

ใครจะไปรู้ว่า Bash นั้นมีอยู่ใน OS X หรือไม่

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