LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 09-01-2016, 10:33 AM   #1
Entropy1024
Member
 
Registered: Dec 2012
Location: UK
Distribution: Ubuntu 16 & 17
Posts: 131

Rep: Reputation: Disabled
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
 
Old 09-01-2016, 10:45 AM   #2
PoleStar
Member
 
Registered: Jul 2010
Posts: 231

Rep: Reputation: 2
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

Last edited by PoleStar; 09-01-2016 at 10:58 AM.
 
Old 09-01-2016, 10:55 AM   #3
Entropy1024
Member
 
Registered: Dec 2012
Location: UK
Distribution: Ubuntu 16 & 17
Posts: 131

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by PoleStar View Post
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
 
Old 09-01-2016, 10:58 AM   #4
keefaz
LQ Guru
 
Registered: Mar 2004
Distribution: Slackware
Posts: 6,552

Rep: Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872
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)
 
Old 09-01-2016, 11:04 AM   #5
PoleStar
Member
 
Registered: Jul 2010
Posts: 231

Rep: Reputation: 2
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)
 
Old 09-01-2016, 11:19 AM   #6
Entropy1024
Member
 
Registered: Dec 2012
Location: UK
Distribution: Ubuntu 16 & 17
Posts: 131

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by PoleStar View Post
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
 
Old 09-01-2016, 11:26 AM   #7
PoleStar
Member
 
Registered: Jul 2010
Posts: 231

Rep: Reputation: 2
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:~ #
 
Old 09-01-2016, 11:32 AM   #8
Entropy1024
Member
 
Registered: Dec 2012
Location: UK
Distribution: Ubuntu 16 & 17
Posts: 131

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by PoleStar View Post
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

Last edited by Entropy1024; 09-01-2016 at 11:43 AM.
 
Old 09-01-2016, 11:54 AM   #9
PoleStar
Member
 
Registered: Jul 2010
Posts: 231

Rep: Reputation: 2
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 "[[ $("
 
Old 09-01-2016, 12:08 PM   #10
Entropy1024
Member
 
Registered: Dec 2012
Location: UK
Distribution: Ubuntu 16 & 17
Posts: 131

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by PoleStar View Post
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
 
Old 09-01-2016, 12:57 PM   #11
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
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.
 
Old 09-01-2016, 01:20 PM   #12
schneidz
LQ Guru
 
Registered: May 2005
Location: boston, usa
Distribution: fedora-35
Posts: 5,313

Rep: Reputation: 918Reputation: 918Reputation: 918Reputation: 918Reputation: 918Reputation: 918Reputation: 918Reputation: 918
Quote:
Originally Posted by grail View Post
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)
 
Old 09-01-2016, 04:30 PM   #13
keefaz
LQ Guru
 
Registered: Mar 2004
Distribution: Slackware
Posts: 6,552

Rep: Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872
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'

Last edited by keefaz; 09-01-2016 at 07:07 PM. Reason: forgot one zero in -gt test
 
Old 09-01-2016, 05:51 PM   #14
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Quote:
Originally Posted by keefaz View Post
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
 
1 members found this post helpful.
Old 09-01-2016, 06:58 PM   #15
allend
LQ 5k Club
 
Registered: Oct 2003
Location: Melbourne
Distribution: Slackware64-15.0
Posts: 6,371

Rep: Reputation: 2749Reputation: 2749Reputation: 2749Reputation: 2749Reputation: 2749Reputation: 2749Reputation: 2749Reputation: 2749Reputation: 2749Reputation: 2749Reputation: 2749
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

Last edited by allend; 09-02-2016 at 03:03 AM.
 
1 members found this post helpful.
  


Reply

Tags
bash, script



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] Script to sort video files into different folders MidKnightLoki Linux - General 1 11-20-2012 05:49 PM
[SOLVED] Bash Script; Sort files into directory based on data in the file name MTAS Programming 31 10-06-2010 11:47 AM
bash script help - finding last n log files in all sub folders jeepescu Programming 4 11-03-2007 07:57 PM
Bash script to sort image files dtcs Programming 5 09-26-2006 09:50 PM
bash script to sort files by extension otheralex Programming 7 08-19-2005 02:40 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 10:23 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration