Je veux utiliser scp
pour télécharger des fichiers mais parfois le répertoire cible peut ne pas exister.
Est-il possible de créer le dossier automatiquement? Si c'est le cas, comment? Sinon, quelle autre façon puis-je essayer?
C'est l'une des nombreuses choses que rsync
peut faire.
Si vous utilisez une version de rsync
publiée au cours des dernières années, ¹ sa syntaxe de commande de base est similaire à scp
: ²
$ rsync -r local-dir remote-machine:path
Cela copiera local-source
et son contenu à $HOME/path/local-dir
sur la machine distante, créant les répertoires nécessaires.³
rsync
a quelques restrictions ici qui peuvent affecter si cela fonctionnera dans votre situation particulière. Il ne créera pas plusieurs niveaux de répertoires distants manquants, par exemple; il ne créera qu'un seul niveau manquant sur la télécommande. Vous pouvez facilement contourner ce problème en précédant la commande rsync
avec quelque chose comme ceci:
$ ssh remote-Host 'mkdir -p foo/bar/qux'
Cela va créer le $HOME/foo/bar/qux
arbre s'il n'existe pas. Il ne se plaindra pas ou ne fera rien de mal si cela existe existe déjà.
rsync
a parfois d'autres comportements surprenants. Fondamentalement, vous lui demandez de comprendre ce que vous vouliez copier, et ses suppositions peuvent ne pas correspondre à vos hypothèses. Essayez-le et voyez. S'il ne se comporte pas comme prévu et que vous ne voyez pas pourquoi, publiez plus de détails sur vos configurations de répertoire local et distant et donnez la commande que vous avez essayée.
Notes de bas de page :
Avant rsync
2.6.0 (1er janvier 2004), il fallait le -e ssh
flag pour qu'il se comporte comme scp
car il est par défaut obsolète protocole RSH .
scp
et rsync
partagent certains indicateurs, mais il n'y a qu'un peu de chevauchement.
Lorsque vous utilisez SSH
comme protocole de transfert, rsync
utilise les mêmes valeurs par défaut. Ainsi, tout comme scp
, il supposera qu'il existe un utilisateur portant le même nom que votre utilisateur local sur la machine distante par défaut.
Si vous copiez un groupe de fichiers, pas vraiment. Si vous copiez un répertoire et tout le contenu en dessous, oui. Étant donné cette commande:
$ scp -pr /source/directory user@Host:the/target/directory
Si directory
n'existe pas dans ~/the/target
sur Host
, il sera créé. Si, toutefois, ~the/target
n'existe pas, vous aurez probablement des problèmes - je ne me souviens pas des résultats exacts de ce cas, mais préparez-vous à l'échec de scp
.
Pour autant que je sache, scp
lui-même ne peut pas faire cela, non. Cependant, vous pouvez simplement ssh
sur la machine cible, créer le répertoire, puis copier. Quelque chose comme:
ssh user@Host "mkdir -p /target/path/" &&
scp /path/to/source user@Host:/target/path/
Notez que si vous copiez des répertoires entiers, ce qui précède n'est pas nécessaire. Par exemple, pour copier le répertoire ~/foo
à l'hôte distant, vous pouvez utiliser le -r
(récursif):
scp ~/foo/ user@Host:~/
Cela va créer le répertoire cible ~/foo
sur l'hôte distant. Cependant, il ne peut pas créer le répertoire parent. scp ~/foo user@Host:~/bar/foo
échouera sauf si le répertoire cible bar
existe. Dans tous les cas, le -r
L'indicateur n'aidera pas à créer un répertoire cible si vous copiez des fichiers individuels.
J'utilise la fonction suivante avant de transférer btrfs
des instantanés sur ssh
:
check_remote_dir() {
printf "\ntesting remote directory: '$1' "
if ssh -p $PORT $ROOT@$REMOTE "[ ! -d $1 ]"; then
printf "\nCreating: $1 on $ROOT@$REMOTE\n"
ssh -p $PORT $ROOT@$REMOTE "mkdir -p $1"
else
printf "[OK]\n"
fi
}
Appelez simplement la fonction dans votre script avec:
check_remote_dir /my/remote/path
Oui, vous pouvez. Selon la page de manuel de scp:
man scp
.....
-r Copie récursivement des répertoires entiers. Notez que scp suit les liens symboliques rencontrés lors de la traversée de l'arbre.
....
Lorsqu'il est limité à scp ou sftp sans ssh disponible (par rssh), il est possible de créer des répertoires en copiant une arborescence de répertoires vide avec rsync puis en copiant des fichiers.
Voilà comment je mets la clé publique ssh sur l'hôte distant lorsque ssh-copy-id ne fonctionne pas et que le répertoire .ssh n'existe pas:
rsync -e 'ssh -p22' -av -f"+ */" -f"- *" ~/.ssh [email protected]:~/
scp -P22 ~/.ssh/id_rsa.pub [email protected]:~/.ssh/authorized_keys
Il est possible de combiner ces commandes en un seul rsync en ajoutant un filtre d'inclusion supplémentaire au milieu, si le nom du fichier cible est le même.
Vous pouvez chaîner la commande avec la commande mkdir puis faire référence au dossier que vous avez créé:
mkdir ~/new-folder/ && scp -P 22 <remote/url>:~/new-folder/
Il s'agit d'un script pour créer une hiérarchie de répertoires cible ne seule fois par répertoire (pas un ssh mkdir -p
Aveugle à chaque fois).
Je copie des enregistrements animés (fichiers vidéo) au fur et à mesure qu'ils sont écrits sur le disque local (événementiel).
rsync
n'a pas de sens car il est inutile de faire des comparaisons de répertoires complètes - je transfère un fichier par événement. Si je restreins rsync à un seul sous-répertoire ou fichier, il ne pourra pas créer la hiérarchie complète du répertoire cible.scp
fonctionnera très bien mais il ne sait pas si le répertoire cible existe, et je ne veux pas exécuter un ssh mkdir -p pour chaque fichier.ssh mkdir
Chaque fois que nous le reverrons. Effacez ce tableau quotidiennement afin qu'il ne devienne pas énorme.#!/bin/bash
TARGETHOST="some.hostname"
TARGETPATH="/data/backups/MOTION/"
ensure_dir() {
if [ "$TODAY" != "$(date +%D)" ] ; then
CREATED=() # reset array daily and first time so it won't get huge
TODAY=$(date +%D)
fi
if [[ ! " ${CREATED[@]} " =~ " ${1} " ]]; then
# create dir
echo "Creating remote directory: $1"
ssh $TARGETHOST "mkdir -p ${TARGETPATH}$1"
CREATED+=("$1")
fi
}
# This line is specific to my use case, watching a directory for new files:
inotifywait -mr --format '%w %f' -e close_write --exclude '.jpg' /data/MOTION/ | while read filedir filename ; do
RELDIR=$(echo $filedir | sed 's|/data/MOTION/||')
ensure_dir "$RELDIR"
echo "Copying '$filename' from '${filedir}' to '${RELDIR}'"
scp -r -p "${filedir}${filename}" "${TARGETHOST}:${TARGETPATH}${RELDIR}${filename}"
done
Creating remote directory: 2019-12-28/movie-C6/
Copying 'test1.mp4' from '/data/MOTION/2019-12-28/movie-C6/' to '2019-12-28/movie-C6/'
Creating remote directory: 2019-12-28/movie-C4/
Copying '095700.mp4' from '/data/MOTION/2019-12-28/movie-C4/' to '2019-12-28/movie-C4/'
Copying '095841.mp4' from '/data/MOTION/2019-12-28/movie-C4/' to '2019-12-28/movie-C4/'
Copying '100410.mp4' from '/data/MOTION/2019-12-28/movie-C4/' to '2019-12-28/movie-C4/'
Creating remote directory: 2019-12-28/movie-C2/
Copying '102106.mp4' from '/data/MOTION/2019-12-28/movie-C2/' to '2019-12-28/movie-C2/'
Creating remote directory: 2019-12-28/movie-C5/
Copying '102318.mp4' from '/data/MOTION/2019-12-28/movie-C5/' to '2019-12-28/movie-C5/'
Copying '102326.mp4' from '/data/MOTION/2019-12-28/movie-C2/' to '2019-12-28/movie-C2/'
Creating remote directory: 2019-12-28/movie-C1/
Copying '102450.mp4' from '/data/MOTION/2019-12-28/movie-C1/' to '2019-12-28/movie-C1/'
Copying '102744.mp4' from '/data/MOTION/2019-12-28/movie-C2/' to '2019-12-28/movie-C2/'
Copying '103008.mp4' from '/data/MOTION/2019-12-28/movie-C2/' to '2019-12-28/movie-C2/'
Copying '103945.mp4' from '/data/MOTION/2019-12-28/movie-C6/' to '2019-12-28/movie-C6/'
Copying '104252.mp4' from '/data/MOTION/2019-12-28/movie-C6/' to '2019-12-28/movie-C6/'
Copying '104824.mp4' from '/data/MOTION/2019-12-28/movie-C6/' to '2019-12-28/movie-C6/'