Comment puis-je créer des répertoires au cours d'une copie en bash / zsh / ksh?
-
13-09-2019 - |
Question
Je reçois les messages suivants souvent, par exemple, lorsque les fichiers d'adaptation dev à une branche maître
cp: /Users/Masi/gitHub/shells/zsh/dvorak: No such file or directory
cp: /Users/Masi/gitHub/shells/zsh/dvorak2: No such file or directory
Je voudrais être interrogé sur la création des dossiers donnés tels que ma commande initiale sera exécutée si je réponds oui à la question (s).
Ma tentative de pseudo-code quand je suis en train de copier un fichier dans un répertoire qui n'existe pas
if no such a directory exists, then asks users about to create it:
if yes, then mkdir directory AND run the initial command again
else do noting
Problèmes
- Pour modifier le message d'avertissement: Quel fichier ne contrôle le "Aucun fichier ou répertoire" -command
- Pour gratter le chemin dans la commande initiale et mkidr chemin sans le fichier : Comment se gratter le chemin dans la commande initiale
- Pour gratter de la fin avec votre langue choisie, comme AWK: Comment supprimer le dernier match dans le chemin quand / est le séparateur de champ? Je ne sais pas comment vous pouvez gratter les lettres à partir de la fin avec AWK.
La solution
Voici une fonction que j'ai écrit qui travaillera en zsh, bash ou ksh.
Remarque: Il a le débogage activé (il fait écho aux commandes qu'il courrait plutôt que de les exécuter). Si vous commentez cette ligne, il sera en fait de les exécuter.
Attention . Il n'a pas été complètement testé
Pour l'utiliser, placez ce script dans un fichier appelé cpmd
dans /usr/local/bin
(ou ailleurs dans votre chemin). Pour l'activer, à partir de l'invite du shell tapez la commande suivante (ou l'ajouter à votre script de démarrage - pour bash il serait ~/.bashrc
):
source cpmd
Ensuite, vous pouvez copier un fichier en utilisant une commande comme ceci:
cpmd carparts /home/dave/Documents/nonexistent/newdir/
Ni répertoire « inexistant » ou « newdir » existent encore. Les deux répertoires sont créés le fichier nommé « carparts » est copié « newdir ».
Si vous ne pas inclure une barre oblique ( « / ») à la fin, la dernière partie est traitée comme un nom de fichier et les répertoires inexistants avant qui sont créés:
cpmd supplies /home/dave/Documents/anothernew/consumables
Le répertoire « anothernew » est créé alors « fournitures » est copié avec le nouveau nom de fichier « consommables ».
Si tous les répertoires dans la destination existent déjà, cpmd
agit comme la commande cp
régulière.
function cpmd {
# copies files and makes intermediate dest. directories if they don't exist
# for bash, ksh or zsh
# by Dennis Williamson - 2009-06-14
# http://stackoverflow.com/questions/993266/unable-to-make-nosuchdirectory-message-useful-in-zsh
# WARNING: no validation is performed on $1 and $2
# all cp commands below are hardcoded with -i (interactive) to prevent overwriting
if [[ -n $KSH_VERSION ]]
then
alias local=typeset
local func="$0"
local lastchar="${2: -1}"
readcmd () { read "$2?$1"; }
elif [[ -n $ZSH_VERSION ]]
then
local func="$0"
# the following two lines are split up instead of doing "${2[-1]}"
# to keep ksh from complaining when the function is loaded
local dest="$2"
local lastchar="${dest[-1]}"
readcmd () { read "$2?$1"; }
elif [[ -n $BASH_VERSION ]]
then
local func="$FUNCNAME"
local lastchar="${2:(-1)}"
readcmd () { read -p "$1" $2; }
else
echo "cpmd has only been tested in bash, ksh and zsh." >&2
return 1
fi
local DEBUG='echo' # COMMENT THIS OUT to make this function actually work
if [[ ${#@} != 2 ]]
then
echo "$func: invalid number of parameters
Usage:
$func source destination
where 'destination' can include nonexistent directories (which will
be created). You must end 'destination' with a / in order for it to
specify only directories. Without the final slash, the 'source' will
be copied with a new name (the last portion of 'destination'). If you
are copying multiple files and 'destination' is not a directory, the
copy will fail." >&2
return 1
fi
local dir=$(dirname "$2")
local response
local nl=$'\n'
# destination ($2) is presumed to be in one of the following formats:
# .../existdir test 1 (-d "$2")
# .../existdir/existfile test 2 (-f "$2")
# .../existdir/newfile test 3 (-d "$dir" && $lastchar != '/')
# .../existdir/newdir/ (else)
# .../newdir/newdir/ (else)
# .../newdir/newfile (else)
if [[ -d "$2" || -f "$2" || (-d "$dir" && $lastchar != '/') ]]
then
$DEBUG cp -i "$1" "$2"
else
if [[ $lastchar == '/' ]]
then
dir="$2"
fi
local prompt="$func: The destination directory...${nl} ${dir}${nl}...does not exist. Create? (y/n): "
while [[ -z $response ]]
do
readcmd "$prompt" response
case $response in
y|Y) response="Y" ;;
n|N) ;;
*) response=
prompt="$func: Invalid response.${nl} Create destination directory? (y/n): ";;
esac
done
if [[ $response == "Y" ]]
then
$DEBUG mkdir -p "$dir" && $DEBUG cp -i "$1" "$2"
else
echo "$func: Cancelled." >&2
fi
fi
}
Autres conseils
Ce message d'erreur provient de la commande cp
, pas zsh. Si vous voulez améliorer la sortie, vous allez devoir écrire la logique pour tronquer et examiner le chemin le long de la vérification pour voir si elle existe ou non.
Il existe des commandes pour aider à cela, un coup d'oeil à basename (1) et dirname (1).