help script in bash with find

Hy, on my leap 15.0 the problem is:
I have many files that have .avi extension but they are matroska files and should have .mkv extension, I never noted this becouse using smplayer it seems that extension is not important, it opens and play flawlessly any file, when I transfere these files in other apparatuses it doesn’t works, the matroska files files must have the .mkv extension.
I would have a script that change the extension of all matroska files in a folder with .avi extension to .mkv extension.
I reached this script that works but on all the avi files:

#!/bin/bash#here under /where/the/files/are
cd /home/procuste/Downloads/prove/
find . -name '*.avi' \
-exec mmv {} {}.mkv \;

I found that using mediainfo I can get if the file is matroska in this way:

mediainfo "name-of-the-file" | grep "Matroska"

I tried to add this option to the working script but I didn’t succeed, the less error version is this:

#!/bin/bash#here under /where/the/files/are
cd /home/procuste/Downloads/prove/
find . -name '*.avi' | 'mediainfo | grep "Matroska"' \
-exec mmv {} {}.mkv \;

could some saint guy gives me a suggestion to solve this problem correcting this script or in another way??
manythanks, ciao :slight_smile:

Well, sorry to say, but your last script isn’t rea;y smething.

But going back, you forgot to tell what

mediainfo "name-of-the-file" | grep "Matroska"

produces as output. And you try to use that output in your script. Bit difficult to give comment.

I can understand what

find . -name '*.avi' -exec mmv {} {}.mkv \;

does. In short it finds, starting from the working directory, looking for filenames that end in .avi. When it finds one, let us say e.g. tune.avi, it then executes the command

mmv tune.avi tune.avi.mkv

Is that would you also think it does?

Now to the second command line

find . -name '*.avi' | 'mediainfo | grep "Matroska"' -exec mmv {} {}.mkv \;

These are two commands connected through a pipe. The first one is

find . -name '*.avi'

This wil find the same files as earlier, but because there is no further thing to do for find, it will output the file names found.
Those file names will then go into the pipe and be fed as input to the next command:

'mediainfo | grep "Matroska"' -exec mmv {} {}.mkv \;

Mind the quotes there ‘…’. They wil make

'mediainfo | grep "Matroska"'

one “word” (the spaces being included because of the quoting) and that, in the end is NOT a command that can be found.

Then if we remove the quoting, we will have again two statements with a pipe in between.

First the simple


will then get fed the file names from the pipe, which it then should read from stdin. And that is different from your earlier usage of mediainfo, when mediainfo does not read from stdin, but gets one file name fed as an argument. Thus I doubt this way of using mediainfo will do what you hope.

The next command after the second pipe

grep "Matroska"' -exec mmv {} {}.mkv \;

Where the grep “Matroska” part can be understood, but the rest is not something that will be handled by grep in a way I (and you) will understand. Syntacticaly it looks like it is part of a find statement, but there is no find statement anymore.

Again, helping you with creating something that is based on the use of mediainfo, we need to know what mediainfo does.

I suggest you start by designing a script that works for a single file, with name given on the command line. That way you can use “grep” in a test to determine whether to rename this file.

Once you have a script that works for a single file, you can then come up with a “find” command that calls your script on each file found.

manythanks hcvv :slight_smile:

the output of mediainfo if the file is a matroska file is:

io@server3TW:~/Downloads/prove> mediainfo mmm.avi | grep "Matroska"
Format                                   : **Matroska**

when the file is not a matroska file is:

procuste@server3TW:~/Downloads/prove> mediainfo aaa.avi | grep "Matroska"    

so I would like to use this difference in output to get only the matroska files that ends with .avi

manythanks nick, I will try also this way :slight_smile:

I would use the feature that grep gives a return code on found/not found.

grep -q "Matroska" tune.avi && mmv tune.avi tune.avi.mkv

So try this first on a file that is Matroska and one that isn’t to see if it works as intended (method nrickert).

Then to call this from a find, there are two ways.

The most simple to uderstand what you are doing is making a script from the above statement, call it e.g. convert:

grep -q "Matroska" ${1}e && mmv ${1} ${1}.mkv

And then do the

find . -name '*.avi" -exec convert {} \;

I have not tested this because I lack the environment you have!

well, this script works:

#!/bin/bash#qui sotto /dir/da/dove/prelevi/i/files
cd /home/procuste/Downloads/prove/
matro=$(mediainfo "mmm.avi" | grep "Matroska")
echo "$matro"
if  -n "$matro" ]; then
mmv 'mmm.avi' 'mmm.mkv'

if mmm.avi is a matroska file it is renamed as .mkv file if it is not a matroska file it remain .avi.
but I don’t now know how to transfere the filename that comes from the “find” command to this script

You will by now have found out that my post was not complete.

The second possibility is to incorporate the statmenet in the fibnd command, but that is more complicated. And it ha one big disadvantage, you will get the tune.avi.mlv file where yoy probably want tune.mkv.

For that you cab adapt the script to

grep -q "Matroska" ${1}e && mmv ${1} ${1%.avi}.mkv

Yes, in this way you convert the grep reult into a logical, but I think my way is shorter and better understandable.

I don’t know what your programs “mediainfo” and “mmv” do. So I’m guessing here.

Try changing your script to:

#! /bin/bash

matro=$(mediainfo "$1" | grep "Matroska")

if  -n "$matro" ]; then
    dir=`dirname "$1"`
    file=`basename "$1" .avi`
    mmv "$dir/$file.avi" "$dir/$file.mkv"

That should allow you to put the filename/path as the an argument to your script. But this depends on your programs working properly with full paths.

If that all works, then you can call your script from a find command – so that it is called for each file.

Correcting the original Bash line:

  • Yes, a Bash “pipeline” connects a command’s “standard output” to another command’s “standard input” but, the 2nd command has to accept “standard input” – not all commands do …

The correct method is to use “xargs” to pass the “standard output” in the pipeline to the 2nd command:

find . -iname '*.avi' -type f -print0 | xargs mediainfo

  • Please notice the use of ‘-iname’ on the “find” command to ensure that the wild-card REALLY means «take notice of upper and lower case characters in the file name» …

  • Using a Bash “pipeline” terminates the command being executed – the “find” command ends at ‘|’ …

Therefore, the “-exec” is meaningless …

  • Using the implicit “-print” of ‘find’ is dangerous – explicitly use “-print0” to ensure that filenames with spaces and new lines will be operated on …
  • Ensure that ‘find’ only considers regular files – “-type f” …

I’m puzzled by the single quote before “mediainfo” – did you want to enable the “backquote” “backtick”] behaviour of Bash?<>
[HR][/HR]I think that, we’re now at the stage where, as pointed out by previous answers, an «if-then-else» or better a «for-do-done» compound command structure is needed to evaluate the filenames which are associated with the “Matroska” file format.
BTW: <> …
[HR][/HR]As an exercise, there’s also the possibility to do this sort of thing in the modern way, with “Perl” or, in the «old-fashioned» way with “awk” …

Up to this point in this thread, it’s all very interesting regarding the scripting but it’s unlikely going to solve the original problem.
The .mkv extension is only file extension associated with the container and is completely separate from the codec (Matroska in this case) that is used to play the file. The .mkv extension is only commonly associated with Matroska encoded files, changing the file extension does nothing to the encoding.

The file extension is more commonly a convenience to assign a particular player to automatically play that type of file, so in this case that possibly would have been the easier solution instead of changing all the file extensions. But, that’s purely an organizational decision… perhaps some AVI files are encoded with something other than Matroska so you want to use the file extensions to use different players to play differently encoded files.

Another approach would to simply (usually) use Mediainfo to verify or identify the encoding so that you can know what the missing codec is, and then locate and install that codec in the player that won’t play the file. In that case, nothing else needs to be done.


My approach in this kind of situation would be to first use Find or Locate to identify where all the files I want are,
Then manually move (or copy) them all into a single folder.
Then use any looping/batch statement to execute whatever I want on each file… in your case either a file renaming or transcoding… whatever you wish.

That would not only simplify but also better organize and be certain where and what is happening.


manythanks tsu, …in my case, using various devices, in many of them if I try to play a matroska file with .avi extension it doesn’t works, if I change the extension to .mkv it works. so may be the problem is specific of my devices :slight_smile:

Manythanks to all you guys :slight_smile: jmergings all yours suggestion:
this is correggimkv5w.txt, the working script with the find command:

#!/bin/bash#here under /where/the/files/are
cd /home/procuste/Downloads/prove/
find . -type f -print0 -iname '*.avi' \
-execdir /home/procuste/Downloads/prove/matro5w.txt '{}' \;

this is matro5w.txt, the working script called by the find command:

#!/bin/bash#here under /where/the/files/are
cd /home/procuste/Downloads/prove/
mediainfo ${1} | grep -q "Matroska" && mmv ${1} ${1%.avi}.mkv

…but they don’t works with filenames with spaces, with or without any of -type f or -print0 or -iname or -name

this is the output:

procuste@server3TW:~/Downloads/prove> ./correggimkv5w.txt  
v./mmm ccc.avi./matro.txt./correggimkv-faifileavivuoti4.txt./matro5w.txt./matro3.txt./aaa.avi./mediainfo./comando-faifilevuot

…any suggestion:-) ciao thanks :slight_smile:

it seems SOLVED ! lol!
moidifiing in this way the script:

#!/bin/bash#here under /where/the/files/are
cd /home/procuste/Downloads/prove/
mediainfo "${1}" | grep -q "Matroska" && mmv "${1}" "${1%.avi}".mkv