nutools/fndate

430 lines
14 KiB
Bash
Executable File

#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
TOOLS=(ddir dfile dcopy dmove dcmd)
if [ "$#" -eq 1 -a "$1" == --nutools-makelinks ]; then
# créer les liens
scriptname="$(basename "$0")"
for tool in "${TOOLS[@]}"; do
ln -s "$scriptname" "$tool"
done
exit 0
fi
source "$(dirname -- "$0")/lib/ulib/auto" || exit 1
function display_help() {
uecho "$scriptname: manipuler des noms de fichier pour les dater
USAGE
$scriptname (FILE|DIR)s...
$scriptname -k SRCs... [DESTDIR]
$scriptname -m SRCs... [DESTDIR]
$scriptname -c COMMAND [ARGs...]
OPTIONS
--create-or-rename
Créer un nouveau fichier (option -f) ou créer un nouveau répertoire
(option -d), ou renommer un fichier existant sans le changer de
répertoire. C'est l'option par défaut.
-f, --create-file
Créer un nouveau fichier. Cette option est ignorée si le fichier ou le
répertoire spécifié existe. C'est la valeur par défaut
-d, --create-dir
Créer un nouveau répertoire. Cette option est ignorée si le fichier ou
le répertoire spécifié existe.
-k, --copy
Copier le fichier SRC vers la destination DESTDIR qui vaut par défaut le
répertoire courant si un seul fichier source est spécifié. Si plusieurs
fichiers sources sont spécifiés, il faut absolument spécifier un
répertoire destination. Dans la destination, les fichiers sont nommés
avec la date en préfixe.
-m, --move
Déplacer le fichier SRC vers la destination DESTDIR qui vaut par défaut
le répertoire courant si un seul fichier source est spécifié. Si
plusieurs fichiers sources sont spécifiés, il faut absolument spécifier
un répertoire destination. Dans la destination, les fichiers sont nommés
avec la date en préfixe.
-c, --cmd
Les arguments sont une commande à lancer. Dans les argument, PLACEHOLDER
est remplacé par la date. Si le PLACEHOLDER n'est trouvé dans aucun des
arguments, alors ajouter la date à la fin de la commande. Par exemple,
voici comment émuler l'option -k
$scriptname -c cp src dest/~~
--string
Remplacer dans chaque argument le placeholder par la date et afficher le
résultat.
-P, --placeholder PLACEHOLDER
Dans le nom spécifié, remplacer PLACEHOLDER par la date. Par défaut,
PLACEHOLDER vaut ~~. Si le nom spécifié ne contient pas le PLACEHOLDER,
il est placé au début.
-@, --force-date DATE
Si une date du format attendu est déjà présente dans le nom du fichier,
forcer son remplacement par la valeur spécifiée. Par défaut, le fichier
n'est pas modifié si la date est déjà présente.
Si le premier ou le dernier argument de ce script ressemblent à une date
(ie. d/m[/y] ou @d[/m[/y]]) et qu'aucun fichier de ce nom n'existe dans
le répertoire courant, activer automatiquement cette option, sauf si
l'option --no-auto-force-date est spécifiée aussi. Ainsi, les commandes
suivantes sont équivalentes:
$scriptname -@ d/m/y file
$scriptname d/m/y file
$scriptname file @d/m/y
-F, --format FORMAT
Spécifier le format de la date à insérer dans le nom du fichier. Par
défaut, FORMAT vaut 'YYMMDD-'
Les formats valides sont:
YYYY année sur 4 chiffres
YY année sur 2 chiffres
MM mois sur 2 chiffres
DD jour sur 2 chiffres
Tous les autres caractères sont pris tels-quels
-s, --short
Equivalent à -F YYMMDD --autof
-l, --long
Equivalent à -F YYYMMDD --autof
--autof
Option non (pas encore) documentée"
}
function create() {
case "$create" in
file) touch "$1";;
dir) mkdir -p "$1";;
esac
}
function have_ph() {
[[ "$1" == *"$placeholder"* ]]
}
function replace_ph() {
local fy fm fd
if [ -n "$force_date" ]; then
fd="${force_date:0:2}"
fm="${force_date:3:2}"
fy="${force_date:6:4}"
fi
awkrun ph="$placeholder" \
force_date="$force_date" fy:str="$fy" fm:str="$fm" fd:str="$fd" \
format="$format" autof:int="$autof" '
function short2long(s, cy, py, sy, ly) {
cy = strftime("%Y") + 0
cy = cy - cy % 100
py = cy - 100
sy = substr(s, 1, 2) + 0
if (sy >= 80) ly = py + sy
else ly = cy + sy
return ly substr(s, 3)
}
BEGIN {
if (format ~ /YYYYMMDD/) type = "long"
else if (format ~ /YYMMDD/) type = "short"
else type = "custom"
if (force_date != "") {
gsub(/%/, "%%", format)
gsub(/YYYY/, fy, format)
gsub(/YY/, substr(fy, 3, 2), format)
gsub(/MM/, fm, format)
gsub(/DD/, fd, format)
} else {
gsub(/%/, "%%", format)
gsub(/YYYY/, "%Y", format)
gsub(/YY/, "%y", format)
gsub(/MM/, "%m", format)
gsub(/DD/, "%d", format)
}
date = strftime(format)
}
{
if (index($0, "/") != 0) {
match($0, /\/[^/]*$/)
dir = substr($0, 1, RSTART)
name = substr($0, RSTART + 1)
} else {
dir = ""
name = $0
}
if (autof) {
pos = index(name, ph)
if (pos == 0) {
if (force_date != "") {
if (type == "long") {
if (name ~ /^[0-9]{8}/) {
name = substr(name, 9)
print dir date name
} else if (name ~ /^[0-9]{6}/) {
name = substr(name, 7)
print dir date name
} else {
print dir date "-" name
}
} else if (type == "short") {
if (name ~ /^[0-9]{8}/) {
name = substr(name, 9)
print dir date name
} else if (name ~ /^[0-9]{6}/) {
name = substr(name, 7)
print dir date name
} else {
print dir date "-" name
}
} else if (type == "custom") {
print dir date "-" name
}
} else {
if (type == "long") {
if (name ~ /^[0-9]{8}/) print dir name
else if (name ~ /^[0-9]{6}/) print dir short2long(name)
else print dir date "-" name
} else if (type == "short") {
if (name ~ /^[0-9]{8}/) print dir substr(name, 3)
else if (name ~ /^[0-9]{6}/) print dir name
else print dir date "-" name
} else if (type == "custom") {
print dir date "-" name
}
}
} else if (pos == 1) {
print dir date "-" substr(name, length(ph) + 1)
} else if (pos == length(name) - length(ph) + 1) {
print dir substr(name, 1, length(name) - length(ph)) "-" date
} else {
print dir substr(name, 1, pos - 1) date substr(name, pos + length(ph))
}
} else {
pos = index(name, ph)
if (pos == 0) {
if (force_date != "") {
if (type == "long") {
if (name ~ /^[0-9]{8}/) name = substr(name, 9)
print dir date name
} else if (type == "short") {
if (name ~ /^[0-9]{6}/) name = substr(name, 7)
print dir date name
} else if (type == "custom") {
print dir date name
}
} else {
if (type == "long") {
if (name ~ /^[0-9]{8}/) print dir name
else print dir date name
} else if (type == "short") {
if (name ~ /^[0-9]{6}/) print dir name
else print dir date name
} else if (type == "custom") {
print dir date name
}
}
} else {
print dir substr(name, 1, pos - 1) date substr(name, pos + length(ph))
}
}
}' <<<"$1"
}
action=create
create=
case "$scriptname" in
ddir) action=create; create=dir;;
dfile) action=create; create=file;;
dcopy) action=copy;;
dmove) action=move;;
dcmd) action=cmd;;
esac
cmd_quiet=
placeholder=
auto_force_date=1
force_date=
format=
autof=
parse_opts "${PRETTYOPTS[@]}" \
--help '$exit_with display_help' \
--create-or-rename action=create \
-d,--create-dir create=dir \
-f,--create-file create=file \
-k,--copy action=copy \
-m,--move action=move \
-c,--cmd action=cmd \
--string action=string \
--cmd-quiet cmd_quiet=1 \
-P:,--placeholder: placeholder= \
--no-auto-force-date auto_force_date= \
-@:,--force-date: force_date= \
-F:,--format: format= \
-s,--short '$format=YYMMDD; autof=1' \
-l,--long '$format=YYYYMMDD; autof=1' \
--autof autof=1 \
@ args -- "$@" && set -- "${args[@]}" || die "$args"
if [ -z "$force_date" -a -n "$auto_force_date" ]; then
# si le premier ou le dernier argument ressemblent à une date
f="$1"; f2="${f#@}"
if [[ "$f" == */* ]] && [ -z "${f//[0-9\/]}" -a ! -e "$f" ]; then
force_date="$f"
shift
elif [[ "$f" == @* ]] && [ -z "${f2//[0-9\/]}" -a ! -e "$f2" ]; then
force_date="$f2"
shift
elif [ $# -gt 1 ]; then
l="${@:$#}"; l2="${l#@}"
if [[ "$l" == */* ]] && [ -z "${l//[0-9\/]}" -a ! -e "$l" ]; then
force_date="$l"
set -- "${@:1:$(($# - 1))}"
elif [[ "$l" == @* ]] && [ -z "${l2//[0-9\/]}" -a ! -e "$l2" ]; then
force_date="$l2"
set -- "${@:1:$(($# - 1))}"
fi
fi
fi
[ -n "$create" ] || create=file
[ -n "$placeholder" ] || placeholder="~~"
[ -n "$force_date" ] && setx force_date=parse_date "$force_date"
if [ -z "$format" ]; then
format=YYMMDD
autof=1
fi
if [ "$action" == cmd ]; then
# Il faut lancer une commande spécifiée
[ $# -gt 0 ] || set -- echo
args=()
found=
for arg in "$@"; do
if have_ph "$arg"; then
[ -z "$cmd_quiet" ] && check_interaction -c && evalx qvals "${args[@]}" "$arg" // estepi "Commande:"
setx arg=replace_ph "$arg" "$force_date"
read_value "Veuillez confirmer le nom" arg "$arg"
found=1
fi
args=("${args[@]}" "$arg")
done
if [ -z "$found" ]; then
setx arg=replace_ph "" "$force_date"
read_value "Veuillez entrer le nom du fichier" arg "$arg"
args=("${args[@]}" "$arg")
fi
if show_debug; then
evalx qvals "${args[@]}" // edebug "Commande effective:"
ask_yesno "Voulez-vous continuer?" X || die
fi
"${args[@]}"
elif [ "$action" == copy -o "$action" == move ]; then
if [ $# -eq 0 ]; then
die "Vous devez spécifier les fichiers"
elif [ $# -eq 1 ]; then
src="$1"
destdir=.
srcs=("$src")
else
args=("$@")
setx destdir=last_value args
array_copy_firsts srcs args
fi
if [ ! -d "$destdir" ]; then
ewarn "$destdir: répertoire introuvable"
ask_yesno "Voulez-vous le créer?" X || die
mkdir -p "$destdir" || die
fi
if [ "$action" == copy ]; then
cmdinfo="Copie"
cmd=(cp -i)
elif [ "$action" == move ]; then
cmdinfo="Déplacement"
cmd=(mv -i)
fi
for src in "${srcs[@]}"; do
setx src=abspath "$src"
setx srcname=basename -- "$src"
if [ -e "$src" ]; then
estep "$cmdinfo de $(ppath "$src")"
setx destname=replace_ph "$srcname" "$force_date"
setx dest=abspath "$destdir/$destname"
[ "$src" != "$dest" ] || ewarn "La source et la destination sont identiques"
read_value "Veuillez confirmer le nom" destname "$destname"
setx dest=abspath "$destdir/$destname"
[ "$src" != "$dest" ] && "${cmd[@]}" "$src" "$destdir/$destname"
else
ewarn "$src: fichier introuvable"
fi
done
elif [ "$action" == create ]; then
if [ $# -gt 0 ]; then
for src in "$@"; do
setx src=abspath "$src"
setx dir=dirname -- "$src"
setx srcname=basename -- "$src"
if [ -e "$src" ]; then
setx destname=replace_ph "$srcname" "$force_date"
setx dest=abspath "$dir/$destname"
confirm_do=1
if [ "$src" == "$dest" ]; then
if [ -n "$force_date" ]; then
ewarn "La source et la destination sont identiques"
else
estepi "$(ppath "$src"): aucun renommage nécessaire"
confirm_do=
fi
fi
if [ -n "$confirm_do" ]; then
estep "Renommage de $(ppath "$src")"
read_value "Veuillez confirmer le nom" destname "$destname"
setx dest=abspath "$dir/$destname"
[ "$src" != "$dest" ] && mv -i "$src" "$dir/$destname"
fi
else
setx destname=replace_ph "$srcname" "$force_date"
setx dest=abspath "$dir/$destname"
if [ -d "$dest" ]; then
ewarn "$srcname --> $(ppath "$dest"): répertoire existant"
elif [ -e "$dest" ]; then
ewarn "$srcname --> $(ppath "$dest"): fichier existant"
else
estep "$srcname --> Création de $(ppath "$dest")"
fi
read_value "Veuillez confirmer le nom" destname "$destname"
setx dest=abspath "$dir/$destname"
create "$dir/$destname"
fi
done
else
setx destname=replace_ph "" "$force_date"
confirm_action=entrer
if [ -d "$destname" ]; then
ewarn "$destname: répertoire existant"
confirm_action=confirmer
elif [ -e "$destname" ]; then
ewarn "$destname: fichier existant"
confirm_action=confirmer
else
case "$create" in
file) estep "Création d'un nouveau fichier";;
dir) estep "Création d'un nouveau répertoire";;
esac
fi
read_value "Veuillez $confirm_action le nom" destname "$destname"
create "$destname"
fi
elif [ "$action" == string ]; then
if [ $# -gt 0 ]; then
for string in "$@"; do
replace_ph "$string" "$force_date"
done
else
replace_ph "" "$force_date"
fi
else
die "$action: action non implémentée"
fi