Jak mogę używać dwóch parametrów jednocześnie z xargs?


18

Muszę konwertować filmy, ale nie wiem, gdzie one są, więc potrzebuję findich. Jak mogę podać wynik i nazwę pliku wyjściowego FFmpeg za pomocą xargs?

Już się dowiedziałem, że mogę skonstruować dwa parametry za pomocą tego polecenia:

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

Nie mogę znaleźć niczego związanego w xargsinstrukcji. Chcę coś takiego:

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

W jaki sposób mogę to zrobić?


Ci z was, którzy natkną się na to pytanie, ponieważ szukają odpowiedzi na wiele argumentów, xargs ogólnie mogą chcieć sprawdzić stackoverflow.com/questions/3770432/… .
Chris Oldwood,

Odpowiedzi:


4

Coś takiego zrobi lewę i zachowa pełną ścieżkę, obsłuży przestrzeń, zmieni nazwę folder/movie.movna folder/movie.flvitp.

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

A jeśli cię źle zrozumiałem i chcesz wszystkie filmy .flv w bieżącym katalogu, użyj tego:

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

3
Jeśli chcesz to jako oneliner, po prostu umieść wszystko w jednym wierszu. ;)
Mattias Ahnberg

9

Powodem, dla którego ludzie używają xargsw połączeniu z find, jest to, że wiele nazw plików zostanie przekazanych do tego samego wywołania programu niezależnie od xargsuruchomionego programu . Na przykład, jeśli findzwraca pliki foo , bar i baz , następujące działania będą działać mvtylko raz:

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

Skutecznie wywołuje mvnastępujące czynności:

mv -t destDir foo bar baz

Jeśli nie potrzebujesz lub nie chcesz tego zachowania (jak zakładam, tak jest tutaj), możesz po prostu użyć find's' -exec.


W takim przypadku łatwym rozwiązaniem byłoby napisanie krótkiego skryptu powłoki, takiego jak:

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

Zapisz jako myffmpeg.shi uruchom chmod +x myffmpeg.sh. Następnie uruchom następujące polecenie:

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

Spowoduje to wywołanie skryptu powłoki raz dla każdego znalezionego pliku. Z kolei skrypt powłoki wyodrębnia nazwę pliku z pełnej ścieżki i wywołuje ffmpegz odpowiednimi argumentami.


4

Nie uzyskałem oczekiwanego przeze mnie rozwiązania, więc odkryłem swoje. @ Odpowiedź Daniela jest dobra, ale wymaga skryptu powłoki. Jedna linijka jest szybsza i bardziej mi się podoba :) również prostsze rozwiązanie niż pisanie skryptu.

Mógłbym użyć jednego argumentu i przetworzyć go za basenamepomocąsh -c

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

-I informuje xargs, aby zastąpił {}bieżącym argumentem.
Dane wyjściowe polecenia wewnątrz `` wydrukowane na standardowe wyjście (funkcja bash), więc basename {}zostaną ocenione jako sama nazwa pliku i wydrukowane.
-0 do prawidłowej obsługi specjalnych nazw plików, ale musisz przekazać parametry z opcją -print0 z find


3

Musisz zrobić to tak, jak wszystkie odpowiedzi tam, ale DOKŁADNE użycie xargs będzie takie:

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

W twoim przypadku będzie to:

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

PS: To odpowiada na pytanie o xargs dla tych, którzy szukają odpowiedzi dokładnie dla wielu xargsparametrów w jednym xargspoleceniu.


1

Dlaczego po prostu nie przesunąć opcji ffmpeg, aby pasowały do ​​formatu wyników polecenia find ?

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

Zwróć uwagę na dodanie opcji -r do xargs, aby zapobiec uruchomieniu ffmpeg, jeśli nie zostaną znalezione żadne pliki .mov .

Dodałem N2 opcję xargs , aby ograniczyć liczbę elementów xargs procesów do dwóch naraz. W tym przypadku elementami są ścieżka do pliku i nazwa pliku. Jeśli nie zostanie ustawiona opcja -n , xargs przetworzy jak najwięcej elementów wejściowych w jednym wykonaniu.


To nie zadziała, gdy więcej niż jeden plik zostanie znaleziony AFAICT.
Daniel Beck

Dla mnie działa to tylko raz, ale nie rozumiem, dlaczego przestaje po pierwszym. Dowolny pomysł ?
kissgyorgy

właściwie to nie działa
kissgyorgy

Daniel-Beck i @Walkman mieli rację co do pojedynczej egzekucji. Aby rozwiązać ten problem, zredagowałem tę odpowiedź, aby ograniczyć liczbę elementów xargs przetwarzanych jednocześnie za pomocą opcji -n2 . Bez N2 , xargs wykonywana tylko raz, czy może obsłużyć liczbę elementów wejściowych otrzymane przez rurę. Należy również zauważyć, że to rozwiązanie działa tylko wtedy, gdy nazwy plików i ścieżki plików nie zawierają białych znaków.
ZaSter

1

Nie jestem pewien, czy możesz i jak to zrobić za pomocą xargs.

Ale coś takiego powinno ci działać:

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

1
To nie obsługuje poprawnie spacji w nazwach / ścieżkach plików, prawda?
Daniel Beck

1

Alternatywa dla odpowiedzi Zoredache'a przy użyciu wiązania nazw (i przy użyciu różnych separatorów, aby uniknąć problemów ze spacjami w nazwach plików):

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

Oczywiście można również użyć separatorów z find -a arrayargumentem, którego użyła druga odpowiedź, ale czasami nazwane argumenty są bardziej zrozumiałe.


0

Możesz uruchomić ffmpeg bezpośrednio z polecenia find w następujący sposób:

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

Zwróć uwagę na cudzysłowy wokół parametrów ffmpeg, na wypadek, gdy w nazwie pliku znajdują się spacje, a średnik, który uciec, oznacza koniec wykonanego polecenia.


Czy masz dokumentację dotyczącą zachowania -exec, która również interpretuje symbole zastępcze formatowania printf?
Daniel Beck

Nie. Mózg pierdnięcie: Myślałem, że% p i% f były znalezionymi rzeczami, a nie printf-rzeczami. Głosowałem na twoją odpowiedź.
Randy Orrison
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.