ฉันจะใช้สองพารามิเตอร์พร้อมกันกับ xargs ได้อย่างไร


18

ฉันต้องการแปลงวิดีโอ แต่ฉันไม่รู้ว่าพวกเขาอยู่ที่ไหนดังนั้นฉันจึงต้องการfindพวกเขา ฉันจะให้ผลลัพธ์และชื่อไฟล์เอาต์พุตแก่FFmpegด้วยได้xargsอย่างไร

ฉันพบแล้วว่าฉันสามารถสร้างพารามิเตอร์ทั้งสองด้วยคำสั่งนี้:

find . -iname "*.mov" -printf "%p %f\n"

ฉันไม่พบสิ่งใดที่เกี่ยวข้องในxargsคู่มือ ฉันต้องการสิ่งนี้:

find . -iname "*.mov" -printf "%p %f\n" | xargs ffmpeg -i {param1} -f flv {param2}

ฉันจะทำสิ่งนี้ได้อย่างไร


บรรดาของคุณสะดุดข้ามคำถามนี้เพราะคุณกำลังมองหาคำตอบเกี่ยวกับข้อโต้แย้งหลายที่มีxargs ทั่วไปอาจต้องการตรวจสอบstackoverflow.com/questions/3770432/...
Chris Oldwood

คำตอบ:


4

บางอย่างเช่นนี้จะทำเคล็ดลับและรักษาเส้นทางแบบเต็มพื้นที่จับเปลี่ยนชื่อfolder/movie.movไปfolder/movie.flvฯลฯ

find . -name "*.mov" | while read movie;do
  ffmpeg -i "$movie" -f flv "${movie%.mov}.flv"
done

และถ้าฉันเข้าใจผิดคุณและคุณต้องการภาพยนตร์. flv ทั้งหมดในไดเรกทอรีปัจจุบันให้ใช้อันนี้แทน:

find . -name "*.mov" | while read movie;do
  ffmpeg -i "$movie" -f flv "$(basename "${movie%.mov}.flv")"
done

3
หากคุณต้องการให้มันเป็นแบบออนไลน์เพียงแค่ใส่ทุกอย่างไว้ในบรรทัดเดียว ;)
Mattias Ahnberg

9

เหตุผลที่ผู้คนใช้xargsร่วมกับการค้นหาคือชื่อไฟล์หลายชื่อจะถูกส่งผ่านไปยังการเรียกใช้โปรแกรมเดียวกันของสิ่งที่xargsเปิดตัวโปรแกรม ตัวอย่างเช่นหากfindส่งคืนไฟล์foo , barและbazสิ่งต่อไปนี้จะทำงานmvเพียงครั้งเดียว:

find sourceDir [...] -print0 | xargs -0 mv -t destDir

อย่างมีประสิทธิภาพมันเรียกร้องmvดังต่อไปนี้:

mv -t destDir foo bar baz

หากคุณไม่ต้องการหรือต้องการพฤติกรรมนี้ (ตามที่ผมถือว่าเป็นกรณีที่นี่) คุณก็สามารถใช้'sfind-exec


ในกรณีนี้ทางออกที่ง่ายคือการเขียนเชลล์สคริปต์แบบสั้นดังต่อไปนี้:

#!/usr/bin/env bash
[[ -f "$1" ]] || { echo "$1 not found" ; exit 1 ; }
P="$1"
F="$( basename $P )"
ffmpeg -i "$P" -f flv "$F"

บันทึกเป็นและเรียกใช้myffmpeg.sh chmod +x myffmpeg.shจากนั้นเรียกใช้สิ่งต่อไปนี้:

find . -iname "*.mov" -exec /path/to/myffmpeg.sh {} \;

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


4

ฉันไม่ได้รับวิธีแก้ปัญหาตามที่คาดหวังดังนั้นฉันค้นพบตัวเอง @ คำตอบของ Daniel นั้นดี แต่มันต้องมีเชลล์สคริปต์ ซับหนึ่งเร็วกว่าและฉันชอบดีกว่า :) และยังแก้ปัญหาได้ง่ายกว่าเขียนสคริปต์

ฉันสามารถใช้อาร์กิวเมนต์หนึ่งและประมวลผลด้วยbasenameและใช้sh -c

find . -iname "*.mov" -print0 | xargs -0 -i sh -c 'ffmpeg -i {} -f flv `basename {}`'

-i บอกกับ xargs เพื่อแทนที่{}ด้วยอาร์กิวเมนต์ปัจจุบัน
เอาต์พุตคำสั่งภายใน `` พิมพ์ออกไปยังเอาต์พุตมาตรฐาน (คุณสมบัติทุบตี) ดังนั้นbasename {}จะถูกประเมินเป็นชื่อไฟล์เปล่าและพิมพ์ออกมา
-0 สำหรับการจัดการชื่อไฟล์พิเศษอย่างถูกต้อง แต่คุณต้องผ่านพารามิเตอร์ด้วยตัวเลือก -print0 พร้อมการค้นหา


3

คุณต้องทำเหมือนทุกคำตอบที่นั่น แต่การใช้ xargs อย่างถูกต้องจะเป็นดังนี้:

echo argument1 argument2 argument3 | xargs -l bash -c 'echo this is first:$0 second:$1 third:$2' | xargs

ดังนั้นในกรณีของคุณมันจะเป็น:

find . -iname "*.mov" -printf "%p %f\n" | xargs -l bash -c 'echo ffmpeg -i $0 -f flv $1' | xargs

PS: นี่ตอบคำถามเกี่ยวกับ xargs สำหรับผู้ที่กำลังมองหาคำตอบที่แน่นอนสำหรับหลายxargsพารามิเตอร์ในxargsคำสั่งเดียว


1

ทำไมไม่เพียงย้ายตัวเลือกของffmpegให้พอดีกับรูปแบบของผลลัพธ์จากคำสั่งfind ?

find . -iname "*.mov" -printf "%p %f\n" | xargs -r -n2 ffmpeg -f flv -i

แจ้งให้ทราบการเพิ่มตัวเลือก-rเพื่อxargsเพื่อป้องกันไม่ให้มันทำงานffmpegถ้าไม่มีพบไฟล์. mov

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


สิ่งนี้จะไม่ทำงานเมื่อพบไฟล์มากกว่าหนึ่งไฟล์ AFAICT
Daniel Beck

ใช้งานได้เพียงครั้งเดียวสำหรับฉันเช่นกัน แต่ฉันก็ไม่เข้าใจว่าทำไมมันถึงหยุดหลังจากแรก ความคิดใด ๆ
kissgyorgy

อันที่จริงมันใช้งานไม่ได้
kissgyorgy

Daniel-Beck และ @Walkman ถูกต้องเกี่ยวกับการประหารชีวิตครั้งเดียว เพื่อแก้ไขปัญหานั้นฉันได้แก้ไขคำตอบนี้เพื่อ จำกัด จำนวนของรายการ xargs กระบวนการในแต่ละครั้งผ่านตัวเลือก-n2 หากไม่มี-n2 , xargsจะเรียกใช้งานเพียงครั้งเดียวหากสามารถจัดการจำนวนรายการอินพุตที่ได้รับผ่านไปป์ มันควรจะชี้ให้เห็นว่าวิธีนี้ใช้ได้เฉพาะเมื่อชื่อไฟล์และเส้นทางไฟล์ไม่รวมถึงช่องว่าง
ZaSter

1

ฉันไม่แน่ใจว่าคุณสามารถหรือวิธีการทำกับ xargs

แต่สิ่งนี้จะเหมาะกับคุณ:

find . -iname "*.mov" -printf "%p %f\n" | while read -a HR ; do echo ffmpeg -i ${HR[0]} -f flv ${HR[1]} ;done

1
สิ่งนี้ไม่ได้จัดการช่องว่างในชื่อไฟล์ / พา ธ อย่างถูกต้องใช่ไหม
Daniel Beck

1

ทางเลือกอื่นสำหรับคำตอบของ Zoredache โดยใช้การผูกชื่อ (และใช้ตัวคั่นอื่นเพื่อหลีกเลี่ยงปัญหาช่องว่างในชื่อไฟล์):

IFS="\t" find -iname "*.mov" -printf "%p\t%f\n" | while read path file; do
    ffmpeg -i $path -f flv $file
done

แน่นอนคุณยังสามารถใช้ตัวคั่นด้วยfind -a arrayอาร์กิวเมนต์ที่คำตอบอื่นใช้ แต่บางครั้งชื่ออาร์กิวเมนต์นั้นเข้าใจได้ง่ายกว่า


0

คุณสามารถรัน ffmpeg โดยตรงจากคำสั่ง find เช่นนี้:

find . -iname "*.mov" -exec ffmpeg -i "%p" -f flv "%f" \;

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


คุณมีเอกสารเกี่ยวกับพฤติกรรมของ -exec ที่ตีความตัวยึดตำแหน่งการจัดรูปแบบ printf หรือไม่
Daniel Beck

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