diriterator/diriterator.sh

141 lines
5.4 KiB
Bash
Raw Normal View History

2016-04-04 23:34:41 +02:00
#!/bin/bash
# set shell options
set -e # abort on first error
shopt -s nullglob # allow filename patterns which match no files to expand to a null string, rather than themselves
2016-04-04 23:34:41 +02:00
shopt -s dotglob
2015-08-01 00:30:13 +02:00
# define queue
queue=()
function queueecho {
2016-04-04 23:34:41 +02:00
for item in "${queue[@]}"; do
echo "$item"
2015-08-01 00:30:13 +02:00
done
}
function queueexec {
queueecho | parallel "-j$parallelcount" --eta "eval {}"
}
function iteratedirs {
local dir="$1"
local depth="$2"
local current_rel_dir="$3"
for item in "$dir"/*; do
2016-04-04 23:34:41 +02:00
if [[ -d $item ]]; then
2017-01-20 22:19:07 +01:00
if [[ $depth == none ]] || [[ $currentlevel -lt $depth ]]; then
iteratedirs "${item}" $(($depth + 1)) "${current_rel_dir}${item##*/}/"
2015-08-01 00:30:13 +02:00
fi
2016-04-04 23:34:41 +02:00
elif [[ -f $item ]]; then
if [[ ! $filter ]] || [[ $item =~ $filter ]]; then
2015-08-01 00:30:13 +02:00
name=${item##*/}
namewithoutextension=${name%.*}
queue+=("ITERATOR_FULL_PATH=\"$item\" ITERATOR_FILE_NAME=\"$name\" ITERATOR_FILE_NAME_WITHOUT_EXTENSION=\"$namewithoutextension\" ITERATOR_CURRENT_DIR=\"$dir\" ITERATOR_CURRENT_REL_DIR=\"$current_rel_dir\" ITERATOR_BASE_DIR=\"$basedir\" ITERATOR_TARGET_DIR=\"$targetdir/$current_rel_dir\" \"$cmd\" $append")
2015-08-01 00:30:13 +02:00
else
echo "${bold}${blue}Info:${normal} ${bold}Skipping »$item«.${normal}"
fi
else
echo "${bold}${yellow}Warning:${normal} ${bold}Item »$item« is neither a directory nor a file and will be skipped.${normal}"
fi
done
}
# determine sequences for formatted output
red=$(tput setaf 1)
green=$(tput setaf 2)
yellow=$(tput setaf 3)
blue=$(tput setaf 4)
bold=$(tput bold)
normal=$(tput sgr0)
# parse arguments
2017-01-20 22:19:07 +01:00
read= argcount=0 append= basedir=. targetdir= depth=none cmd= filter= parallelcount=+0 noconfirm=
2015-08-01 00:30:13 +02:00
for arg in "$@"
do
2017-01-20 22:36:44 +01:00
if [[ $arg == --base-dir ]]; then
2015-08-01 00:30:13 +02:00
read=basedir
2017-01-20 22:36:44 +01:00
elif [[ $arg == --depth ]]; then
2017-01-20 22:19:07 +01:00
read=depth
2017-01-20 22:36:44 +01:00
elif [[ $arg == --cmd ]]; then
2015-08-01 00:30:13 +02:00
read=cmd
2017-01-20 22:36:44 +01:00
elif [[ $arg == --filter ]]; then
2015-08-01 00:30:13 +02:00
read=filter
2017-01-20 22:36:44 +01:00
elif [[ $arg == --args ]]; then
2015-08-01 00:30:13 +02:00
read=arguments
2017-01-20 22:36:44 +01:00
elif [[ $arg == --parallel-count ]]; then
2015-08-01 00:30:13 +02:00
read=parallelcount
2017-01-20 22:36:44 +01:00
elif [[ $arg == --target-dir ]]; then
2015-08-01 00:30:13 +02:00
read=target
2017-01-20 22:36:44 +01:00
elif [[ $arg == --no-confirm ]]; then
2015-08-01 00:30:13 +02:00
noconfirm=true
2017-01-20 22:36:44 +01:00
elif [[ $arg == --help ]] || [[ $arg == -h ]]; then
2015-08-01 00:30:13 +02:00
echo "${bold}Runs a script for each file in a directory hierarchy using GNU parallel.${normal}
2017-01-20 22:36:44 +01:00
--base-dir base directory (current directory by default)
--target-dir target directory (base directory by default)
--depth maximal recursion depth (unlimited by default)
--cmd command to be executed
--filter regular expression to filter files, eg. ${bold}.*\.((mp4$)|(mp3$))${normal}
--args arguments to be passed to cmd
--no-confirm generated commands will be executed without prompt for confirmation
--parallel-count maximal number of commands to be executed parallel
2015-08-01 00:30:13 +02:00
${bold}The following environment variables will be set when running the script:${normal}
2017-01-20 22:36:44 +01:00
ITERATOR_FULL_PATH current file path
ITERATOR_FILE_NAME current file name with extension
ITERATOR_FILE_NAME_WITHOUT_EXTENSION current file name without extension
ITERATOR_CURRENT_DIR current directory
ITERATOR_BASE_DIR base directory (specified using --base-dir)
ITERATOR_CURRENT_REL_DIR current directory (relative to the base directory)
ITERATOR_TARGET_DIR target directory for the current file
2015-08-01 00:30:13 +02:00
"
exit 0
else
if [[ $read == arguments ]]; then
append="$append \"$arg\""
elif [[ $read == basedir ]]; then
basedir=$arg
2017-01-20 22:19:07 +01:00
elif [[ $read == depth ]]; then
if ! [[ $arg =~ ^[0-9]+$ ]]; then
echo "${bold}${red}Error:${normal} ${bold}specified depth »$arg« is not an unsigned number.${normal}"
2015-08-01 00:30:13 +02:00
exit 1
fi
2017-01-20 22:19:07 +01:00
depth=$arg
2015-08-01 00:30:13 +02:00
elif [[ $read == cmd ]]; then
cmd=$arg
elif [[ $read == filter ]]; then
filter=$arg
elif [[ $read == parallelcount ]]; then
parallelcount=$arg
elif [[ $read == target ]]; then
targetdir=$arg
else
echo "${bold}${red}Error:${normal} ${bold}Invalid argument »$arg« specified.${normal}"
exit 1
fi
if [[ $read != arguments ]]; then
read=
fi
fi
done
# validate specified arguments, use base directory as target directory if not specified
[[ $targetdir ]] || targetdir=$basedir
2016-04-04 23:34:41 +02:00
if [[ ! $cmd ]]; then
2015-08-01 00:30:13 +02:00
echo "${bold}${red}Error:${normal} ${bold}No command specified.${normal}"
exit 1
fi
# start recursive iteration and exec queue
iteratedirs "$basedir" 0
if [[ ${#queue[@]} -ge 1 ]]; then
echo "${bold}Generated queue${normal}"
queueecho
if [[ $noconfirm ]]; then
2015-08-01 00:30:13 +02:00
queueexec
else
while true; do
2016-04-04 23:34:41 +02:00
read -p "${bold}Do you want to execute ${#queue[@]} commands [y/n]?${normal} " yn
2015-08-01 00:30:13 +02:00
case $yn in
2016-04-04 23:34:41 +02:00
[Yy]*) queueexec; break;;
[Nn]*) exit;;
*) echo "${bold}Please answer yes or no.${normal}";;
2015-08-01 00:30:13 +02:00
esac
done
fi
else
echo "${bold}${yellow}Warning:${normal} ${bold}Queue is empty.${normal}"
fi