0

Doing my best to make this work but have little knowledge of scripting. This script should be scanning my specified directory and all subdirs scanning video assets moving any corrupted/errored files to the 00errors folder which has been created.

I can get everything to work accept scanning all the sub dirs. Any help would be greatly appreciated.

#!/bin/bash

ROOTPATH="/Volumes/ARC-RAID/STORAGE/ASSET-Processing/Movies/LANDSCAPE/BRAND-RECOVERED/BRAND-RECOVERED-LANDSCAPE "
for subdir in *; do
  cd ${ROOTPATH}/${subdir}
  mkdir 00errors
  
  for path in *.{MOV,mov,MP4,mp4}; do

    ffmpeg -i "${path}" -f null -; echo$?
    RC=$?

    if [ "${RC}" -ne "0" ]; then
        # Do something to handle the error.
        mv ${path} ./00errors
    fi

  done
  cd ../
done
4
  • You haven't been very specific about (a) what you expect to happen and (b) what is actually happening, but I suspect you want for subdir in "${ROOTPATH}"/*; do cd "${subdir}" ...; cd - – steeldriver Mar 2 at 2:58
  • @steeldriver thank you. I have little knowledge in this area and have no idea what the modification you suggested does differently. I replaced [ for subdir in *; do cd ${ROOTPATH}/${subdir} ] with what you suggested and now the command just errors on every file in the main dir and does nothing. If you can provide me with what you think the proper and actual code would be that would be amazing. – Jason Paul Michaels Mar 2 at 17:17
  • Can you be more specific than "just errors"? the only other thing I just noticed is that your ROOTPATH appears to have a trailing space character - is that intentional? – steeldriver Mar 2 at 17:55
  • ... also echo$? will result in an error; echo $?; RC=$? will result in RC containing the exit status of echo (if you want to both echo $? and test it, save the value first). You may find www.shellcheck.net helpful – steeldriver Mar 2 at 19:02
0

Not looking too carefully at your code but suggesting that you use find instead:

#!/bin/sh

topdir=/Volumes/ARC-RAID/STORAGE/ASSET-Processing/Movies/LANDSCAPE/BRAND-RECOVERED/BRAND-RECOVERED-LANDSCAPE

find "$topdir" -name 00error -prune -o \
    -type f \( -iname '*.mp4' -o -iname '*.mov' \) \
    ! -exec ffmpeg -i {} -f null /dev/null \; \
    -execdir mkdir -p 00error \; \
    -execdir mv -- {} 00error \;

Or, calling a short in-line sh script from find:

#!/bin/sh

topdir=/Volumes/ARC-RAID/STORAGE/ASSET-Processing/Movies/LANDSCAPE/BRAND-RECOVERED/BRAND-RECOVERED-LANDSCAPE

find "$topdir" -name 00error -prune -o \
    -type f \( -iname '*.mp4' -o -iname '*.mov' \) -exec sh -c '
    for pathname do
        if ! ffmpeg -i "$pathname" -f null /dev/null; then
            dirpath=${pathname%/*}
            mkdir -p "$dirpath"/00error
            mv "$pathname" "$dirpath"/00error
        fi
    done' sh {} +

Both of these variations assume that you have a find that understands -iname for matching a pattern case-insensitively against filenames, and that it understands -execdir, which executes a utility in the directory of the found file. Both -iname and -execdir are non-standard.

This would pick up any movie file anywhere under the top directory, so it's not as strict about the directory structure as your script.


About your code:

  • I notice that the value of ROOTPATH has a space at the end. This is possibly accidental.

  • echo$? will try to execute something like echo0 or echo1 or something similar, due to the missing space between echo and $?.

  • Fixing the above typo would cause the shell to overwrite $? with the exit status of echo, so $RC would later not reflect the exit status of ffmpeg, but that of echo.

  • Rather than saving the exit status of a command in a separate variable and then testing this against zero, use the command directly in the if statement. I did this in the second variation of the find command above.

  • * may match both directory names and the names of non-directories. Using cd ${ROOTPATH}/${subdir} could therefore fail (it could also fail due to spaces in directory names, like that space at the end of ROOTPATH that you have, or due to the directory being empty). If that cd fails, your inner loop could potentially process the wrong files, and the cd .. further down would bring you up a level too high.

This is a corrected variant of your code:

#!/bin/bash

topdir=/Volumes/ARC-RAID/STORAGE/ASSET-Processing/Movies/LANDSCAPE/BRAND-RECOVERED/BRAND-RECOVERED-LANDSCAPE

# Make globbing case-insensitive (nocaseglob), and
# make patterns disappear if not matched (nullglob)
shopt -s nullglob nocaseglob

for subdir in "$topdir"/*/; do
    for mov in "$subdir"/*.{mov,mp4}; do
        if [ -f "$mov" ] && ! ffmpeg -i "$mov" -f null /dev/null; then
            mkdir -p "$subdir"/00error &&
            mv "$mov" "$subdir"/00error
        fi
    done
done

As you see, cd is not necessary.

Without the inner loop:

#!/bin/bash

topdir=/Volumes/ARC-RAID/STORAGE/ASSET-Processing/Movies/LANDSCAPE/BRAND-RECOVERED/BRAND-RECOVERED-LANDSCAPE

shopt -s nocaseglob nullglob

for mov in "$topdir"/*/*.{mov,mp4}; do
    if [ -f "$mov" ] && ! ffmpeg -i "$mov" -f null /dev/null; then
        mkdir -p "${mov%/*}"/00error &&
        mv "$mov" "${mov%/*}"/00error
    fi
done

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.