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ć?

kissgyorgy
źródło
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
Mattias Ahnberg
źródło
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.

Daniel Beck
źródło
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

kissgyorgy
źródło
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.

sauliux zyziux
źródło
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.

ZaSter
źródło
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
Zoredache
źródło
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.

wolf1oo
źródło
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.

Randy Orrison
źródło
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