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.