LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Bash Script to sort video files to correct folders (https://www.linuxquestions.org/questions/linux-newbie-8/bash-script-to-sort-video-files-to-correct-folders-4175588493/)

Entropy1024 09-01-2016 10:33 AM

Bash Script to sort video files to correct folders
 
I have a little Bash script set up to find video files then move them to a certain folder depending on size. It works fine. An extract of the script I used is below:

Code:

find /home/tim/readynas/Tim/Download/Downloaded/ -type f \( -iname \*.mkv -o -iname \*.avi -o -iname \*.wmv -o -iname \*.mp4 -o -iname \*.m4v \) -size +2G -exec mv -f {} /home/tim/readynas/Videos/Longform/ \;
I then have a similar script to sort video files smaller than 2gig. I thought it would be more elegant, especially as more conditions are added, to break it down using boolean logic as outlined below

If file ends in .mkv or .mp4 or .avi then
If file larger than 2 gig then move to long
If file smaller than 2 gig then move to short

However I'm unsure how this would look in a script. Can I do something like:

Code:

if /home/tim/readynas/Tim/Download/Downloaded/ -type f \( -iname \*.mkv -o -iname \*.avi -o -iname \*.wmv -o -iname \*.mp4 -o -iname \*.m4v \) then
    if -size +2G -exec mv -f {} /home/tim/readynas/Videos/Longform/ \;
    if -size -2G -exec mv -f {} /home/tim/readynas/Videos/Shortform/ \;
else
endif

Many thanks for any help.
Regards
Tim

PoleStar 09-01-2016 10:45 AM

Code:

for i in $(find /home/tim/readynas/Tim/Download/Downloaded/ -type f \( -iname \*.mkv -o -iname \*.avi -o -iname \*.wmv -o -iname \*.mp4 -o -iname \*.m4v \); do

 
    if [[ $(ls -l $i  | awk '{print $5}') -gt 2147483648 ]];then
        mv -f $i /home/tim/readynas/Videos/Longform/
        echo $i moved to Longform
    elif [[ $(ls -l $i  | awk '{print $5}') -lt 2147483648 ]];then
          mv -f $i /home/tim/readynas/Videos/Shortform/
          echo $i moved to Shortform
    else

done


Entropy1024 09-01-2016 10:55 AM

Quote:

Originally Posted by PoleStar (Post 5599308)
for i in $( /home/tim/readynas/Tim/Download/Downloaded/ -type f \( -iname \*.mkv -o -iname \*.avi -o -iname \*.wmv -o -iname \*.mp4 -o -iname \*.m4v \); do


if [[ $(ls -l $i | ls -l | awk '{print $5}') -gt 10000]];then
mv -f $i /home/tim/readynas/Videos/Longform/
elif [[ $(ls -l $i | ls -l | awk '{print $5}') -lt 10000 ]];then
mv -f $i /home/tim/readynas/Videos/Shortform/
else

done

Many thanks for the code. I'm attempting to wrap my head around it.

Does the first line create a string called 'i' that contains all files ending with desired extension?
The next line then lists 'i' then pipes to list again?
Whats the print $5 do?

Sorry, I'm pretty new to Bash
Cheers

keefaz 09-01-2016 10:58 AM

It could be more elegant visually (?) but not efficiently wise than using 2 lines of find command maybe with xargs to move all found filenames in one go (for each line)

PoleStar 09-01-2016 11:04 AM

This should print the name of all the file you intend do find.

Code:

for i in $(find /home/tim/readynas/Tim/Download/Downloaded/ -type f \( -iname \*.mkv -o -iname \*.avi -o -iname \*.wmv -o -iname \*.mp4 -o -iname \*.m4v \); do
 
 echo $i

done


do this
Code:

ls -l  <some dir eg /tmp>
to find file size in bytes do. Size is # five in the out put.
So we print it out.

Code:

ls -l  <some dir eg /tmp>  | awk '{print $5}'

but when we do this
Code:

  $(ls -l  <some FILENAME>  | awk '{print $5}')
we take that size, position # five, in that variable , so we can use it.

for example do this
Code:

date

echo today is  $(date)


Entropy1024 09-01-2016 11:19 AM

Quote:

Originally Posted by PoleStar (Post 5599321)
This should print the name of all the file you intend do find.

Code:

for i in $(find /home/tim/readynas/Tim/Download/Downloaded/ -type f \( -iname \*.mkv -o -iname \*.avi -o -iname \*.wmv -o -iname \*.mp4 -o -iname \*.m4v \); do
 
 echo $i

done


do this
Code:

ls -l  <some dir eg /tmp>
to find file size in bytes do. Size is # five in the out put.
So we print it out.

Code:

ls -l  <some dir eg /tmp>  | awk '{print $5}'

but when we do this
Code:

  $(ls -l  <some FILENAME>  | awk '{print $5}')
we take that size, position # five, in that variable , so we can use it.

for example do this
Code:

date

echo today is  $(date)



That's great information. I'm slowly figuring it all out.

When I attempt to run the script I get:

/home/tim/bin/download_clean_sort.sh: line 30: unexpected EOF while looking for matching `)'
/home/tim/bin/download_clean_sort.sh: line 64: syntax error: unexpected end of file

I thought that by adding a second ) just before the ; would fix it but I then get more errors. Where should that second ) go?

Cheers
Tim

PoleStar 09-01-2016 11:26 AM

inux-6e72:~ # for i in $(find /etc/init.d -type f \( -iname \*.sh \)); do echo $i ; done

/etc/init.d/mw_APCH.sh
/etc/init.d/test.sh
linux-6e72:~ #

Entropy1024 09-01-2016 11:32 AM

Quote:

Originally Posted by PoleStar (Post 5599332)
inux-6e72:~ # for i in $(find /etc/init.d -type f \( -iname \*.sh \)); do echo $i ; done

/etc/init.d/mw_APCH.sh
/etc/init.d/test.sh
linux-6e72:~ #

Yup, that's what I did then I got the following:

/home/tim/bin/download_clean_sort.sh: line 32: syntax error in conditional expression: unexpected token `;'
/home/tim/bin/download_clean_sort.sh: line 32: syntax error near `;t'
/home/tim/bin/download_clean_sort.sh: line 32: `if [[ $(ls -l $i | ls -l | awk '{print $5}') -gt 10000]];then'

I tried adding a space after the ; but this did not work either.

OK figured out it needed a space after the 10000 :)

PoleStar 09-01-2016 11:54 AM

Code:

linux-6e72:~ # ls -l /etc/init.d/*\.sh
-rwxr--r-- 1 root root 7774 Sep  1 10:34 /etc/init.d/mw_APCH.sh
-rwxr--r-- 1 root root  551 Sep  1 10:12 /etc/init.d/test.sh

[/QUOTE]
[QUOTE]
linux-6e72:~ # for i in $(find /etc/init.d  -type f \( -iname \*.mkv -o -iname \*.avi -o -iname \*.sh \) ) ; do  if [[ $( ls -l $i | awk '{print $5}') -gt 4000  ]]; then  echo $i  large ;  elif  [[ $( ls -l $i | awk '{print $5}') -lt 4000 ]]; then  echo $i small ;  fi  ; done


/etc/init.d/mw_APCH.sh large
/etc/init.d/test.sh small

linux-6e72:~ #

it works. now lets break it down carefully.

Code:

#!/bin/bash

for i in $(find /etc/init.d  -type f \( -iname \*.mkv -o -iname \*.avi -o -iname \*.sh \) )
 do 
    if [[ $( ls -l $i | awk '{print $5}') -gt 4000  ]]; then 
      echo $i  large 
    elif  [[ $( ls -l $i | awk '{print $5}') -lt 4000 ]]; then
      echo $i small   
    fi 
done

please mind the space between "4000 ]]" or "[[ $("

Entropy1024 09-01-2016 12:08 PM

Quote:

Originally Posted by PoleStar (Post 5599352)
Code:

linux-6e72:~ # ls -l /etc/init.d/*\.sh
-rwxr--r-- 1 root root 7774 Sep  1 10:34 /etc/init.d/mw_APCH.sh
-rwxr--r-- 1 root root  551 Sep  1 10:12 /etc/init.d/test.sh


Code:


       
Quote:

       
       
               
       
       

                       

                       
                                linux-6e72:~ # for i in $(find /etc/init.d  -type f \( -iname \*.mkv -o -iname \*.avi -o -iname \*.sh \) ) ; do  if [[ $( ls -l $i | awk '{print $5}') -gt 4000  ]]; then  echo $i  large ;  elif  [[ $( ls -l $i | awk '{print $5}') -lt 4000 ]]; then  echo $i small ;  fi  ; done


/etc/init.d/mw_APCH.sh large
/etc/init.d/test.sh small

linux-6e72:~ #
                       
                       

               


Quote:


it works. now lets break it down carefully.

Code:

#!/bin/bash

for i in $(find /etc/init.d  -type f \( -iname \*.mkv -o -iname \*.avi -o -iname \*.sh \) )
 do 
    if [[ $( ls -l $i | awk '{print $5}') -gt 4000  ]]; then 
      echo $i  large 
    elif  [[ $( ls -l $i | awk '{print $5}') -lt 4000 ]]; then
      echo $i small   
    fi 
done

please mind the space between "4000 ]]" or "[[ $("
Loving your code. Many thanks indeed for all the help, learned a lot.

Cheers for all your time and patience
Tim

grail 09-01-2016 12:57 PM

I would add some cautioning to the current solution:

1. If any of the file names have white space in them the for loop solution will fail

2. Should your default long listing output differ on future machines the ls / awk combination will also fail

As it is working for you in its current form these are not a concern at this point :)


However, a safer solution would be to use a while loop and then something like stat to get the size of the files.

schneidz 09-01-2016 01:20 PM

Quote:

Originally Posted by grail (Post 5599380)
I would add some cautioning to the current solution:

1. If any of the file names have white space in them the for loop solution will fail

2. Should your default long listing output differ on future machines the ls / awk combination will also fail

As it is working for you in its current form these are not a concern at this point :)


However, a safer solution would be to use a while loop and then something like stat to get the size of the files.

yes, and perhaps using file to determine file type. i.e.-
Code:

[schneidz@mom moo-vees]$ file white-men-cant-jump.mkv
white-men-cant-jump.mkv: RIFF (little-endian) data, AVI, 512 x 288, 29.97 fps, video: DivX 5, audio: MPEG-1 Layer 3 (stereo, 48000 Hz)


keefaz 09-01-2016 04:30 PM

One liner:
Code:

find /home/tim/readynas/Tim/Download/Downloaded/ \
-type f \( -iname \*.mkv -o -iname \*.avi \
-o -iname \*.wmv -o -iname \*.mp4 -o -iname \*.m4v \) | \
xargs -I {} bash -c \
's=$(stat --printf="%s" {});\
if [ $s -gt 2200000000 ]; then \
mv -t /home/tim/readynas/Videos/Longform {}; else \
mv -t /home/tim/readynas/Videos/Shortform {}; fi'


grail 09-01-2016 05:51 PM

Quote:

Originally Posted by keefaz (Post 5599472)
One liner:
Code:

find /home/tim/readynas/Tim/Download/Downloaded/ \
-type f \( -iname \*.mkv -o -iname \*.avi \
-o -iname \*.wmv -o -iname \*.mp4 -o -iname \*.m4v \) | \
xargs -I {} bash -c \
's=$(stat --printf="%s" {});\
if [ $s -gt 220000000 ]; then \
mv -t /home/tim/readynas/Videos/Longform {}; else \
mv -t /home/tim/readynas/Videos/Shortform {}; fi'


aaaaaannnnnnnnndddddddd ... yuck :cry:

allend 09-01-2016 06:58 PM

Without involving find:
Code:

#!/bin/bash

topdir="/home/tim/readynas/Tim/Download/Downloaded/"
cd "$topdir"

longform="/home/tim/readynas/Videos/Longform/"
shortform="/home/tim/readynas/Videos/Shortform/"

(( limit=2*1024*1024*1024 ))

shopt -s globstar

for f in **/*.{avi,m4v,mkv,mp4,wmv}; do
 (( $(stat -c %s "$f") > limit )) && mv "$f" "$longform" || mv "$f" "$shortform"
done

shopt -u globstar



All times are GMT -5. The time now is 06:18 PM.