Come posso creare directory durante una copia in bash / zsh / ksh?
-
13-09-2019 - |
Domanda
Ottengo i seguenti messaggi, spesso, ad esempio quando copia i file dev ad un ramo maestro
cp: /Users/Masi/gitHub/shells/zsh/dvorak: No such file or directory
cp: /Users/Masi/gitHub/shells/zsh/dvorak2: No such file or directory
Vorrei essere chiesto circa la creazione delle cartelle indicate in modo tale che il mio comando iniziale sarà eseguito se rispondo di sì alla domanda (s).
Il mio tentativo in pseudo-codice quando sto cercando di copiare un file in una directory che non esiste
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
Problemi
- Per modificare il messaggio di avviso:? Quale file non controllare il "No such file or directory" -command
- Per raschiare il percorso nel comando AND mkidr percorso iniziale senza il file :? Come avrebbe raschiare il percorso nel comando iniziale
- Per raschiare dalla fine con la lingua scelta come AWK: Come si rimuovere l'ultima partita nel percorso quando / è il separatore di campo? io non sono sicuro di come si può raschiare le lettere a partire dalla fine con AWK.
Soluzione
Ecco una funzione che ho scritto, che funzionerà in zsh, bash o ksh.
Nota: E 'il debugging abilitato (si fa eco i comandi sarebbe correre piuttosto che la loro esecuzione). Se si commenta che la linea, sarà effettivamente eseguirli.
Attenzione :. non è stato accuratamente testato
Per usarlo, mettere questo script in un file chiamato cpmd
in /usr/local/bin
(o altrove nel vostro percorso). Per attivarlo, dal prompt della shell digitate il seguente comando (o aggiungere al vostro script di avvio - per bash sarebbe ~/.bashrc
):
source cpmd
Quindi è possibile copiare un file utilizzando un comando come questo:
cpmd carparts /home/dave/Documents/nonexistent/newdir/
Né directory "inesistente" o "newdir" esiste ancora. Entrambe le directory sono create quindi il file denominato "carparts" vengono copiati "newdir".
Se non si include una barra ( "/") alla fine, l'ultima parte viene trattato come un nome di file e le directory inesistenti prima che si creano:
cpmd supplies /home/dave/Documents/anothernew/consumables
La directory "anothernew" viene creato quindi "forniture" viene copiato con il nuovo nome "di consumo".
Se esistono già tutte le directory nella destinazione, cpmd
si comporta come il comando normale cp
.
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
}
Altri suggerimenti
Questo messaggio di errore è venuta dal comando cp
, non zsh. Se si vuole migliorare l'output, si sta andando ad avere per scrivere la logica per troncare ed esaminando il percorso lungo con il controllo per vedere se esiste o meno.
Non ci sono i comandi per assistere con questo, hanno uno sguardo al nome base (1) e dirname (1).