Bagaimana saya bisa menggunakan dua parameter sekaligus dengan xargs?

18

Saya perlu mengkonversi video, tetapi saya tidak tahu di mana mereka, jadi saya perlu findmereka. Bagaimana saya bisa memberikan hasil dan nama file output ke FFmpeg dengan xargs?

Saya sudah tahu bahwa saya dapat membangun dua parameter dengan perintah ini:

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

Saya tidak dapat menemukan apa pun yang terkait dalam xargsmanual. Saya ingin sesuatu seperti ini:

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

Bagaimana saya bisa melakukan ini?

kissgyorgy
sumber
Bagi Anda yang tersandung pada pertanyaan ini karena Anda sedang mencari jawaban tentang beberapa argumen xargs secara umum mungkin ingin memeriksa stackoverflow.com/questions/3770432/… .
Chris Oldwood

Jawaban:

4

Sesuatu seperti ini akan melakukan trik dan mempertahankan jalur penuh, menangani ruang, mengganti nama folder/movie.movmenjadi folder/movie.flv, dll.

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

Dan jika saya salah mengerti Anda dan Anda ingin semua film .flv di direktori saat ini, gunakan yang ini:

find . -name "*.mov" | while read movie;do
  ffmpeg -i "$movie" -f flv "$(basename "${movie%.mov}.flv")"
done
Mattias Ahnberg
sumber
3
Jika Anda menginginkannya sebagai oneliner, letakkan semuanya dalam satu baris. ;)
Mattias Ahnberg
9

Alasan yang digunakan orang xargsdalam kombinasi dengan find adalah bahwa banyak nama file akan diteruskan ke permohonan program yang sama dengan xargspeluncuran program apa pun . Misalnya, jika findmengembalikan file foo , bar , dan baz , berikut ini akan berjalan mvhanya sekali:

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

Secara efektif, ini memanggil mvseperti berikut:

mv -t destDir foo bar baz

Jika Anda tidak perlu atau ingin perilaku ini (seperti yang saya asumsikan adalah kasus di sini), Anda dapat menggunakan find's -exec.


Dalam hal ini, solusi mudahnya adalah dengan menulis skrip shell pendek, seperti berikut:

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

Simpan sebagai myffmpeg.shdan jalankan chmod +x myffmpeg.sh. Kemudian, jalankan yang berikut:

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

Ini akan memanggil skrip shell sekali untuk setiap file yang ditemukan. Script shell pada gilirannya mengekstrak nama file dari path lengkap, dan memanggil ffmpegdengan argumen yang sesuai.

Daniel Beck
sumber
4

Saya tidak mendapatkan solusi yang saya harapkan, jadi saya menemukan solusi sendiri. @ Jawaban Daniel itu bagus, tetapi perlu skrip shell. Satu liner lebih cepat, dan saya menyukainya lebih baik :) juga solusi yang lebih sederhana daripada menulis skrip.

Saya bisa menggunakan satu argumen dan memprosesnya dengan basenamedan menggunakansh -c

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

-I Memberitahu xargs untuk mengganti {}dengan argumen saat ini.
Output perintah di dalam `` dicetak ke output standar (fitur bash) sehingga basename {}akan dievaluasi sebagai nama file kosong dan dicetak.
-0 untuk menangani nama file khusus dengan benar, tetapi Anda harus memberikan parameter dengan opsi -print0 dengan find

kissgyorgy
sumber
3

Anda harus melakukannya seperti semua jawaban di sana, tetapi penggunaan xargs yang TEPAT akan menjadi seperti ini:

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

Jadi dalam kasus Anda itu adalah:

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

PS: Ini menjawab pertanyaan tentang xargs untuk mereka yang mencari jawaban tepat untuk beberapa xargsparameter dalam satu xargsperintah.

sauliux zyziux
sumber
1

Mengapa tidak memindahkan opsi ffmpeg agar sesuai dengan format hasil dari perintah find ?

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

Perhatikan penambahan opsi -r ke xargs untuk mencegahnya menjalankan ffmpeg jika tidak ditemukan file .mov .

Saya telah menambahkan opsi -n2 ke xargs untuk membatasi jumlah item yang diproses xargs menjadi dua sekaligus. Dalam hal ini, item adalah path file dan nama file. Jika opsi no -n diatur, xargs akan memproses item input sebanyak mungkin dalam satu eksekusi.

ZaSter
sumber
Ini tidak akan berfungsi setelah lebih dari satu file ditemukan AFAICT.
Daniel Beck
Ini hanya berfungsi sekali untuk saya juga, tapi saya tidak mengerti mengapa itu berhenti setelah yang pertama. Ada ide ?
kissgyorgy
sebenarnya tidak berhasil
kissgyorgy
Daniel-Beck dan @Walkman benar tentang eksekusi tunggal. Untuk mengatasi masalah itu, saya telah mengedit jawaban ini untuk membatasi jumlah proses xargs item sekaligus melalui opsi -n2 . Tanpa -n2 , xargs dieksekusi hanya sekali jika ia dapat menangani jumlah item input yang diterimanya melalui pipa. Ini juga harus menunjukkan bahwa solusi ini hanya berfungsi ketika nama file dan jalur file tidak termasuk spasi.
ZaSter
1

Saya tidak yakin apakah Anda bisa atau bagaimana melakukannya dengan xargs.

Tetapi sesuatu seperti ini seharusnya bekerja untuk Anda:

find . -iname "*.mov" -printf "%p %f\n" | while read -a HR ; do echo ffmpeg -i ${HR[0]} -f flv ${HR[1]} ;done
Sakit kepala
sumber
1
Ini tidak menangani spasi dengan benar dalam nama file / jalur, bukan?
Daniel Beck
1

Alternatif jawaban Zoredache menggunakan pengikatan nama (dan menggunakan pemisah yang berbeda untuk menghindari masalah spasi dalam nama file):

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

Tentu saja Anda juga dapat menggunakan pemisah dengan find -a arrayargumen yang digunakan oleh jawaban lain, tetapi terkadang argumen yang disebut lebih mudah dipahami.

wolf1oo
sumber
0

Anda dapat menjalankan ffmpeg langsung dari perintah find seperti ini:

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

Perhatikan tanda kutip di sekitar parameter ke ffmpeg, jika ada spasi dalam nama file, dan tanda titik dua yang lolos menandai akhir dari perintah yang dieksekusi.

Randy Orrison
sumber
Apakah Anda memiliki dokumentasi untuk perilaku -exec yang juga mengartikan printf placeholder pemformatan?
Daniel Beck
Nggak. Brain fart: Saya berpikir% p dan% f adalah benda-benda, bukan benda-benda cetakan. Saya telah memilih jawaban Anda.
Randy Orrison