Como posso usar dois parâmetros ao mesmo tempo com xargs?


18

Preciso converter vídeos, mas não sei onde eles estão, por isso preciso finddeles. Como posso dar o resultado e um nome de arquivo de saída para FFmpeg com xargs?

Eu já descobri que posso construir os dois parâmetros com este comando:

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

Não consigo encontrar nada relacionado no xargsmanual. Eu quero algo como isto:

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

Como posso fazer isso?


Aqueles de vocês que se deparam com essa pergunta porque estão procurando uma resposta sobre vários argumentos xargs em geral podem querer consultar stackoverflow.com/questions/3770432/… .
Chris Oldwood

Respostas:


4

Algo assim fará o truque e preservará o caminho completo, manipulará o espaço, renomeará folder/movie.movpara folder/movie.flvetc.

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

E se eu o entendi errado e você deseja todos os filmes .flv no diretório atual, use este:

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

3
Se você quiser um oneliner, basta colocar tudo em uma linha. ;)
Mattias Ahnberg

9

O motivo pelo qual as pessoas usam xargsem combinação com o find é que vários nomes de arquivos serão passados ​​para a mesma chamada de programa de qualquer programa xargsiniciado. Por exemplo, se findretornar os arquivos foo , bar e baz , o seguinte será executado mvapenas uma vez:

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

Efetivamente, ele chama mvda seguinte maneira:

mv -t destDir foo bar baz

Se você não precisa ou deseja esse comportamento (como eu assumo é o caso aqui), você pode simplesmente usar find's -exec.


Nesse caso, uma solução fácil seria escrever um script de shell curto, como o seguinte:

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

Salve como myffmpeg.she execute chmod +x myffmpeg.sh. Em seguida, execute o seguinte:

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

Isso chamará o script de shell uma vez para cada arquivo encontrado. O script de shell, por sua vez, extrai o nome do arquivo do caminho completo e chama ffmpegcom os argumentos apropriados.


4

Não obtive a solução que esperava, então descobri a minha. A resposta de @ Daniel é boa, mas precisa de um script de shell. Um liner é mais rápido, e eu gosto mais :) também solução mais simples do que escrever um script.

Eu poderia usar um argumento e processá-lo com basenamee usandosh -c

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

O -i diz ao xargs para substituir {}o argumento atual.
A saída de comando dentro de `` impressa na saída padrão (recurso bash) basename {}será avaliada como o nome do arquivo e impressa.
-0 para manipular nomes de arquivos especiais corretamente, mas você precisa passar parâmetros com a opção -print0 com find


3

Você precisa fazer isso como todas as respostas, mas o uso exato do xargs será algo como isto:

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

Portanto, no seu caso, será:

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

PS: Isso responde à pergunta sobre xargs para quem está procurando uma resposta exatamente para vários xargsparâmetros em um xargscomando.


1

Por que não simplesmente mover as opções do ffmpeg para ajustar o formato dos resultados no comando find ?

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

Observe a adição da opção -r ao xargs para impedir a execução do ffmpeg se nenhum arquivo .mov for encontrado.

Eu adicionei o N2 opção para xargs para limitar o número de itens xargs processos para dois de cada vez. Nesse caso, os itens são o caminho e o nome do arquivo. Se nenhuma opção -n estiver definida, o xargs processará o maior número possível de itens de entrada em uma única execução.


Isso não funcionará depois que mais de um arquivo for encontrado AFAICT.
Daniel Beck

Isso funciona apenas uma vez para mim também, mas eu não entendo por que ele pára após o primeiro. Qualquer ideia ?
kissgyorgy

na verdade, ele não funciona
kissgyorgy

Daniel-Beck e @Walkman estavam corretos sobre a execução única. Para resolver esse problema, editei esta resposta para limitar o número de itens que o xargs processa por vez através da opção -n2 . Sem o -n2 , o xargs é executado apenas uma vez se puder manipular o número de itens de entrada que recebe através do canal. Também deve ser salientado que esta solução funciona apenas quando nomes e caminhos de arquivos não incluem espaços em branco.
precisa saber é o seguinte

1

Não tenho certeza se você pode ou como fazer isso com xargs.

Mas algo assim deve funcionar para você:

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

11
Isso não lida corretamente com espaços em nomes de arquivo / caminhos, não é?
Daniel Beck

1

Uma alternativa à resposta do Zoredache usando a associação de nomes (e usando diferentes separadores para evitar a questão de espaços nos nomes dos arquivos):

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

Obviamente, você também pode usar os separadores com o find -a arrayargumento usado pela outra resposta, mas às vezes os argumentos nomeados são mais compreensíveis.


0

Você pode executar o ffmpeg diretamente no comando find desta maneira:

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

Observe as aspas ao redor dos parâmetros em ffmpeg, caso haja espaços no nome do arquivo, e o ponto-e-vírgula escapado marca o final do comando executado.


Você possui documentação para o comportamento de -exec que também interpreta espaços reservados de formatação printf?
Daniel Beck

Não. Peido cerebral: eu estava pensando que% p e% f eram coisas de encontrar, não coisas de impressão. Votei na sua resposta.
Randy Orrison
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.