Using a randomfile in folder? - bash

Right now my Script looks like that:
ffmpeg -re -stream_loop -1 -i videos/fitness"$(( RANDOM % 8 ))".mp4
It searches for all videos in my folder that starts with "fitness".
fitness1.mp4
fitness2.mp4
fitness3.mp4
and so on...
and it takes 1 randomly between 1-8 ( im using /fitness"$(( RANDOM % 8 ))".mp4 )
Is there a way to just use a random mp4 file from the folder, no matter whats the name is?

Shuf
Use the shuf command:
shuf -en1 dir/*.mp4
If you don't have shuf (for instance on BSD), you can write your own shuf -en1 very easily:
shufen1() {
shift "$((RANDOM % $#))" # slightly biased towards small numbers, at most 32767
printf %s\\n "$1"
}
Pure bash solution using arrays
For completeness, here is a pure bash solution. However, this has the same problems as the self-written shufen1 function.
a=(dir/*.mp4)
printf %s\\n "${a[RANDOM % ${#a[#]}]}"
Using these solutions
Both commands work under the assumption that there is at least one mp4-file written in lowercase letters. You can use case insensitive matching using shopt -s nocaseglob.
You might want to set shopt -s failglob to get an error in case there is no such file, otherwise the literal string dir/*.mp4 will be printed.
To use any of these solutions, write them into a subshell:
ffmpeg -re -stream_loop -1 -i "$(shuf -en1 videos/*.mp4)"
ffmpeg -re -stream_loop -1 -i "$(a=(videos/*.mp4); printf %s\\n "${a[RANDOM % ${#a[#]}]}")"

find videos -type f -name '*.mp4' | shuf -n1
Find files with the name *.mp4, randomly permute the list of names and output a single filename.
ffmpeg -re -stream_loop -1 -i "$(find videos -type f -name '*.mp4' | shuf -n1)"

Related

Text file content match if else image Resolution

I'm working on a project where I need to cat out the images and videos Resolution if they are not equal script should exit.
I've used command to cat the image Resolution. In this example I've 2 images. In a directory
find $PWD -iname "*.jpg" -type f -exec identify -format '%i %wx%h\n' '{}' \;|awk '{print $NF}'
OUTPUT 1280x720
640x362
I want them both to match if the file size is say it should say Okay else Check the file resolution and exit.
I tried the command to convert the output in to two variables a1 and a2. But it is not working. I tried to copy paste the output to the terminal than it is working. Please help
find $PWD -iname "*.jpg" -type f -exec identify -format '%i %wx%h\n' '{}' \;|awk '{print $NF}'|egrep -n "x"|sed 's#:#=#g'|sed 's#^#a#g'|paste -sd ";"|bash
You did
... | awk '{print $NF}'
and got
1280x720
640x362
I would harness GNU AWK as follows to check if all sizes match
... | awk '{arr[$NF]+=1}END{print length(arr)==1?"Everything match":"At least one mismatch"}'
Which will print either Everything match or At least one mismatch. Explanation: I use array arr for every encountered resolution I increase value for that resolution by 1. At END if arr has exactly 1 distinct key I print Everything match otherwise At least one mismatch using ternany operator i.e. condition?valueiftrue:valueiffalse.
(tested in gawk 4.2.1)

rename files from id3v1 tags in terminal

I have a directory of mp3 files which are all named 1.mp3, 2.mp3 etc..
#dir with numbers for names
10.mp3 15.mp3 2.mp3 24.mp3 29.mp3 33.mp3 38.mp3 42.mp3 47.mp3 51.mp3 56.mp3 60.mp3 65.mp3 7.mp3 74.mp3 79.mp3 83.mp3 88.mp3 92.mp3
11.mp3 16.mp3 20.mp3 25.mp3 3.mp3 34.mp3 39.mp3 43.mp3 48.mp3 52.mp3 57.mp3 61.mp3 66.mp3 70.mp3 75.mp3 8.mp3 84.mp3 89.mp3 93.mp3
12.mp3 17.mp3 21.mp3 26.mp3 30.mp3 35.mp3 4.mp3 44.mp3 49.mp3 53.mp3 58.mp3 62.mp3 67.mp3 71.mp3 76.mp3 80.mp3 85.mp3 9.mp3 94.mp3
13.mp3 18.mp3 22.mp3 27.mp3 31.mp3 36.mp3 40.mp3 45.mp3 5.mp3 54.mp3 59.mp3 63.mp3 68.mp3 72.mp3 77.mp3 81.mp3 86.mp3 90.mp3 95.mp3
14.mp3 19.mp3 23.mp3 28.mp3 32.mp3 37.mp3 41.mp3 46.mp3 50.mp3 55.mp3 6.mp3 64.mp3 69.mp3 73.mp3 78.mp3 82.mp3 87.mp3 91.mp3 96.mp3
I wrote a for loop to extract the title from the metadata using ffmpeg:
for x in *.mp3; do
ffmpeg -i $x ./$("ffmpeg -i $x 2>&1 |grep -E '^\s*title\s*\:\s.*$' |awk -F ' :' '{print $2}'".mp3
done
Instead of extracting the title and renaming the file it says that the file '.mp3' already exists, would I like to rewrite it. when I type y to rewrite this new '.mp3' the same things just happens again.
I fixed the problem by putting the full path of the output file in double quotes instead of just the title extraction command
for x in *.mp3; do
ffmpeg -I $x "./$(ffmpeg -i $x 2>&1 |grep -E '^\s*title\s*\:\s.*$' |awk -F ' :' '{print $2}'
)".mp3
done
My question is why does it create a new file called .mp3 when I only wrap the title extraction command in quotes and not the whole path?
I'm sorry if this is a little lengthly, Im new to stack overflow
In the command substitution $(command), you should not wrap the command
with double quotes as $("command") especially when the command includes
options and/or pipeline sequences, because the double-quoted string is
treated as a single command.
Please see the difference of
echo $("ls")
and
echo $("ls -la")
The 1st one will work but the 2nd one does not, because bash interpretes
ls -la as a single command, not the ls command followed by -la option.
BTW if you just want to rename the files, without re-encoding (which may degrade the quality), you can
say:
for f in *.mp3; do
title=$(ffmpeg -i "$f" 2>&1 | awk '/title/ {sub(/.*title\s*:\s*/, ""); print; exit}')
mv -i -- "$f" "$title".mp3
done
The last exit is for the edge case the mp3 file includes multiple title metadata.
[Update]
As #llogan comments, the ffprobe is more robust to extract the media information
of the file. Please try instead:
for f in *.mp3; do
title=$(ffprobe -v error -of csv=p=0 -show_entries format_tags=title "$f")
mv -- "$f" "$title".mp3
done

Merging video in a specific order using ffmpeg

I use the following to merge video in numeric order.
for f in *; do mv "$f" "${f: -17}"; done &&. find *.ts|. sed 's:\:\ :g'| sed 's/^/file /' > fraglist.txt && ffmpeg -f concat -safe 0 -i fraglist.txt -c copy output.ts; rm fraglist.txt
This works great for files named like the following...
000001
000002
000003
000004
000005
000006
000007
000008
000009
000010
But If I need something like the following merged the order is based on how many digits there are in the file name...
1708.ts 9803.ts 13798.ts 17815.ts 21804.ts 25819.ts
29832.ts
What command could I use to get the second group of files merged in that order? Thank you for your help!
Simplify your whole process by using printf alone to make the txt file contents, and use sort to provide natural/version sorting:
printf "file '%s'\n" *.ts | sort -V > fraglist.txt
ffmpeg -f concat -i fraglist.txt -c copy output.ts
Result:
file '1708.ts'
file '9803.ts'
file '13798.ts'
file '17815.ts'
file '21804.ts'
file '25819.ts'
file '29832.ts'
No need to rm fraglist.txt as the sort redirect (>) will overwrite fraglist.txt.
Note that I removed -safe 0 (an option specific to the concat demuxer) from the ffmpeg command because you don't need it in this exact example. But if you get the Unsafe file name error (such as due to special characters including spaces) then you will need to add it.

How to remove extra spaces in od output when reading from /dev/random

I'm making a script to auto-generate a url with a random number at a specific location. This will be for calling a JSON API for a random endpoint. The end goal is to generate something like this:
curl -s http://api.openbeerdatabase.com/v1/beers/<RAND_INT>.json | jq '.'
where <RAND_INT> is a randomly-generated number. I can create this random number with the following command:
$ od -An -N2 -i /dev/random
126
I do not know why the 10 extra spaces are in the output. When I chain the above commands together to generate the URL, I get this:
$ echo http://api.openbeerdatabase.com/v1/beers/`od -An -N2 -i /dev/random`.json
http://api.openbeerdatabase.com/v1/beers/ 43250.json
As you see, there is a single extra space in the generated URL. How do I avoid this?
I've also tried subshelling the rand_int command $(od -An -N2 -i /dev/random) but that produces the same thing. I've thought about piping the commands together, but I don't know how to capture the output of the rand_int command in a variable to be used in the URL.
As the comments show, there's more than one way to do this. Here's what I would do:
(( n = $( od -An -N2 -i /dev/urandom ) ))
echo http://api.openbeerdatabase.com/v1/beers/${n}.json
Or, to put it in one line:
echo http://api.openbeerdatabase.com/v1/beers/$(( $( od -An -N2 -i /dev/urandom ) )).json
Or, just use ${RANDOM} instead, since bash provides it, although its values top out at 32767, which might be one reason you preferred your od-based method.

Bash - Passing sorted glob to command input

I have a series of images with the file names
motorist_intensity_2.jpg
...
...
motorist_intensity_256.jpg
ad I want to make an animated gif from them using ImageMagick. Now, the command
convert -delay 100 -loop 0 motorist_intensity_* motorist.gif
works, but the frames are out of sorted order. I can produce a sorted file list using
ls motorist_intensity_* | sort -n -t _ -k 3
but how can I pass that list to the covert commad in place of the origial globmotorist_intensity_*?
You can use brace expansion to expand in the order you want:
convert -delay 100 -loop 0 motorist_intensity_{2..256}.gif motorist.gif
The following should work:
convert -delay 100 -loop 0 `ls motorist_intensity_* | sort -n -t _ -k 3` motorist.gif
By putting the command ls ...etc in back quotes, it gets executed and the output is inserted
update
It is preferable to use the $() technique for evaluating an expression (see comments below); also, I am not 100% sure that the output of sort won't include newlines that mess you up. Solving both problems:
convert -delay 100 -loop 0 $(ls motorist_intensity_* | sort -n -t _ -k 3 | xargs echo ) motorist.gif
The xargs echo is a nice shorthand for "Take each of the lines of output of the input in turn, and echo them to the output without the newline". It is my preferred way of converting multiple lines to a single line (although there are many others).
PS - This does not solve the problem you would get if the filename contained a newline. I am assuming they don't...

Resources