0

I'm trying to move file based on pattern via Bash Script.

I use find to select all my camcorder Files and stock result into TXT File.

Each of my camcorder file contain year location, I woule like to use Grep or something to find this string (year in 4 digits ie 1984) and compare this string to move file on different folder, if the file is after 1984 then my file must go in folder "Marie", if the file is before or egual to 1984 it must go to folder "Marie_Liam".

I've try several things, with Grep and while read -r line, but when I compare found string (year) my script return everytime after 1984 ...

Here are my different try :

I've try several things like this (it's a lot of try, not just one script) :

Base script :

#!/bin/bash
find /home/CamFiles/ -name "*.m2ts"

Try 1 :

TestScriptResultFile="/home/Dio/CamCorderFindResult.file"
do
  if [ grep -e " 1984 " "$in" ];
  then
    echo "Voici un film qui est avant 1984 $FindMovie"
  else
    echo "Voici un film qui est de 1984 : $FindMovie"
  fi;
done

-- Another Try --

while IFS= read -r line; do
  if [[ /bin/grep -E "[1][9][8][4]" "$MyLine" != 0 ]] ;
  then
    echo "Ok"
  fi
done < "$TestScriptResultFile"
while read line; do
  if  echo "$line" | grep -q "[1][9][8][4]"; then echo "$line"; fi
  Found=$(echo "$line" | grep -q "[1][9][0-8][0-4]")
  if [[ " $Found " <= 1984 ]]; then echo "$line"; fi
done < "$TestScriptResultFile"
exit 0

-- Another Try --

while read MyLine
do
  if grep -E "$MyPattern" "$MyLine"
  then
    echo "tourne apres 1984 : $MyLine"
  else
    echo "Tourne avant 1984 : $MyLine"
  fi
done < "$TestScriptResultFile"

Thanks for your help.

Best regards.

4
  • I've added my different try to my original post
    – Dio
    Commented Sep 13, 2016 at 16:41
  • I think all of your files contains string 1984. To read exifinfo it's better to use exiftool or exiftran Commented Sep 13, 2016 at 16:59
  • This can be done without that information but it would be much simpler if you wrote a couple of lines of the names of your files to show where the year appears. If its place is constant, then the solution is short and obvious.
    – user556625
    Commented Sep 13, 2016 at 17:41
  • Year is'nt the only one string, On some file I have local postal code (where the movie was record), or range date expressing lenght of stay, and on some files I don't have any date ... I can't use media tag, all my files was restored from a server RAID 6 crash (electric flash), and my files are for some corrupt and for all without any tags ... So I must use file name to order like it was before the crash ...
    – Dio
    Commented Sep 14, 2016 at 10:22

1 Answer 1

0

I've updated the scripts based on the file name examples that you provided in your comment:

"Liam sur la moto (VHS) (2001) - Maison 13100.m2ts" 
"M&L Plage 1080i (2012) - Camargue 30240.m2ts

I came up with two methods to handle this naming convention.

The first is to assume that in every case the year is enclosed in parenthesis. I updated the 'first' script to reflect that case; it's simply an update to the regex pattern that is used.

regexPat='\(\K[0-9]{4,4}(?=\))'

The second script was updated to show a different method, where we can't be sure the year is surrounded by parenthesis. Here we read out the result from the grep evaluation as an array in case there are multiple matches, and then do a sanity check on the year - i.e the year must be between 1970 and 2020; otherwise we assume its not a year.


Note that the readarray command (aka mapfile) is only in Bash versions 4.x+. At the bottom is a more portable version using just read. It can be tricky to parse the output of find without things breaking due to spaces or specials characters in the filenames.

Script 1


#!/bin/bash
# Create test files
touch abcd\({2001,1985,1984,1931}\)efgh.m2ts
touch abcd{24001,198a5,19b84,1912331,1293}.m2ts
touch "abcd 1232 adffd.m2ts"
touch "Liam sur la moto (VHS) (2001) - Maison 13100.m2ts"
touch "M&L Plage 1080i (2012) - Camargue 30240.m2ts" 
TestScriptResultFile="./CamCorderFindResult.file"
touch $TestScriptResultFile
   
regexPat='\(\K[0-9]{4,4}(?=\))'

readarray fileList <<<"$(IFS="\n" ; find . -name "*.m2ts" -exec basename {} \;)"
for i in "${fileList[@]}"; do 
  echo "Processing File: $i"
  if year=$(grep -oP "$regexPat" <<<"$i");    then
    if [ "$year" -le 1984 ]; then
      echo "1984 or earlier: $i" >> "$TestScriptResultFile"
    else
      echo "After 1984: $i" >> "$TestScriptResultFile"
    fi
  else
    echo "No valid year found in file $i"
  fi
done

1. Using the find command to get a file list and store it an array using readarray.

  • Set the field seperator to a new line: IFS=$'\n'
  • Use an -exec argument in find which will run basename on each file to get only the filename and not the path.
  • The find output is directed into an array by using command substitution and a 'Here String', <<< and the readarray command

2. Loop on the array of filenames

3. Use grep and regexPat to find the embedded year

  • The regex pattern I used will match on 6 characters in a string when the first character is a (, followed by exactly 4 numbers [0-9]{4,4}, and closed out by a ) at the end.

  • In order to output only the 4 numbers in between (hopefully the year), the argument -P is given to grep for 'Perl Regex' which allows seperating matched characters from captured (output) characters, among other things.

  • The /K will cause grep to not output anything that matches prior to the /K in the pattern (aka a look-ahead).

  • Finally, the closing ) is removed from the output by using a look-behind non-capture similar to the /K. You can use the basically the same syntax for both, the bottom script shows the look-ahead method that doesn't use /K.

  • the -o flag tells grep to only output the captured, matching portion of the string, which in our case will be a 4 digit number.

The rest of the script checks the number against 1984 and logs it accordingly.


Here's another more compact approach.

2 things to notice here

  • find is given the argument -print0 which will null terminate the output.
  • The read command is given the argument -d '', which tells it its input is null terminated. A null string is usually written\0 in plain text; in Bash you can use '' or $'\0'

Script 2


#!/bin/bash

TestScriptResultFile="./CamCorderFindResult.file"
touch $TestScriptResultFile

regexPat='(?<=[^0-9])[0-9]{4,4}(?=[^0-9])'
find . -name "*.m2ts" -print0 | while IFS= read -r -d '' k; do
  i="$(basename "$k")"
   echo "Processing File: $i"
     if year=($(grep -oP "$regexPat" <<<"$i")); then
     for yr in "${year[@]}"; do
       if [ "$yr" -lt 1970 ] || [ "$yr" -gt 2020 ]; then
         echo "   x Out of range year ($yr) parsed from $i"
       else
         echo "   o Found year $yr"
         if [ "$yr" -le 1984 ]; then
           echo "1984 or earlier: $i" >> "$TestScriptResultFile"
         else
           echo "After 1984: $i" >> "$TestScriptResultFile"
         fi
      fi
     done
   else
     echo "   x No valid year found in file $i"
  fi
done
14
  • Hello Agonauts, A very big thanks for your script ! I've try each and no one is working as expected the first is blocked for each first digit, so if my file have 02-1980 or 720i for camcorder format process fail : Dio@Dio:~#: ./StackOverFlow.sh: line 11: [: 1986 720: integer expression expected Processing File: "Liam sur la moto (VHS) (2001) - Maison 13100.m2ts" ./StackOverFlow.sh: line 11: [: 2001 1080: integer expression expected Processing File: "M&L Plage 1080i (2012) - Camargue 30240.m2ts" ./StackOverFlow.sh: line 11: [: 2012 1080: integer expression expected
    – Dio
    Commented Sep 14, 2016 at 11:31
  • I had to guess at the file naming method. Post some full examples of the names and I'll make sure it works with them.
    – Argonauts
    Commented Sep 14, 2016 at 11:32
  • Ok, thank you, You can see below a couple of my file name : Liam & Marie - Noel (1999) (DVR) Maison.avi Liam 1985 - Etang (VHS) 84120.mp4 Marie - 1979 VHS Chez Francois.mp4 Marie - 1979 - Premiere Noel Maison (VHS).mp4 Liam - 1er match de Foot (1991) (720i).avi Liam - Anniversaire avec les copains (2006) (1080p).m2ts Vacances en Famille 2004 - (1080p).m2ts L&M Chez Tonton 12-02-1993 vhs.avi Marie remise diplome (1999).avi I have also some file who are in .mkv and .webm, they was self produced few years ago if they can be sorted as others are it would be nice! Thanks for your help !
    – Dio
    Commented Sep 14, 2016 at 19:01
  • I think the 2nd script should be effective for those files; for the other extensions you'll have to tweak the find statement. If you get stuck post a response.
    – Argonauts
    Commented Sep 14, 2016 at 19:29
  • Script won't work : x No valid year found in file abcd1912331.m2ts Processing File: abcd1293.m2ts x No valid year found in file abcd1293.m2ts Processing File: abcd 1232 adffd.m2ts x No valid year found in file abcd 1232 adffd.m2ts Processing File: Liam sur la moto (VHS) (2001) - Maison 13100.m2ts x No valid year found in file Liam sur la moto (VHS) (2001) - Maison 13100.m2ts Processing File: M&L Plage 1080i (2012) - Camargue 30240.m2ts x No valid year found in file M&L Plage 1080i (2012) - Camargue 30240.m2ts
    – Dio
    Commented Sep 15, 2016 at 12:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .