Unix - créer le chemin des dossiers et des fichiers

126

Je sais que vous pouvez faire mkdirpour créer un répertoire et touchpour créer un fichier, mais n'y a-t-il aucun moyen de faire les deux opérations en une seule fois?

c'est-à-dire si je veux faire ce qui suit lorsque le dossier othern'existe pas:

cp /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt

Erreur:

cp: cannot create regular file `/my/other/path/here/cpedthing.txt': No such file or directory

Quelqu'un a-t-il proposé une fonction pour contourner ce problème?

haut
la source
1
Trouvé ceci: stackoverflow.com/questions/1529946/…
Bjørne Malmanger
S'il est essentiel que la création du fichier et de son répertoire soit atomique, il faudrait écrire un système de fichiers qui propose cette opération. Ce n'est pas possible avec les systèmes de fichiers Linux standard.
Peter G.10
@toop Je comprends que cette question a maintenant un an et demi, mais plusieurs réponses y ont été récemment fusionnées. Si vous avez besoin de ce type de chose très souvent, vous trouverez peut-être ma réponse utile. (Je dirais plus utile que la réponse acceptée, mais je ne demande pas de représentant ici :-))
Jonathon Reinhart
Trouvé ceci: stackoverflow.com/a/8722721/29182
Ziggy
@tdammers Q: "Comment faire X?" R: "Voici comment faire Y"
Henry Henrinson

Réponses:

140

Utilisez &&pour combiner deux commandes dans une seule ligne de shell:

COMMAND1 && COMMAND2
mkdir -p /my/other/path/here/ && touch /my/other/path/here/cpedthing.txt

Remarque: Auparavant, je recommandais d'utiliser ;pour séparer les deux commandes, mais comme indiqué par @trysis, il est probablement préférable de l'utiliser &&dans la plupart des situations, car en cas d' COMMAND1échec, COMMAND2il ne sera pas exécuté non plus. (Sinon, cela pourrait entraîner des problèmes auxquels vous ne vous attendiez peut-être pas.)

évotopide
la source
16
Il est probablement préférable d'utiliser &&, comme avec ;, si la première commande échoue, la deuxième commande sera toujours exécutée (et échouera aussi, car ce répertoire n'existe pas encore). Avec &&si la première commande échoue, la deuxième commande ne s'exécute pas.
trysis le
12
Une coupe courte pour l'exemple de code peut être: mkdir -p /my/other/path/here && touch $_/cpredthing.txt. Le se $_développe essentiellement pour devenir le "dernier argument de la dernière commande exécutée".
Sgnl
4
@Sgnl yours est sans doute la bonne réponse. Ce n'est pas seulement plus propre, il est moins sujet aux erreurs.
Choylton B.Higginbottom
3
Je souhaite vraiment touchprendre un -pparamètre comme le mkdirfait.
Ben174
86

Vous devez d'abord créer tous les répertoires parents.

FILE=./base/data/sounds/effects/camera_click.ogg

mkdir -p "$(dirname "$FILE")" && touch "$FILE"

Si vous voulez faire preuve de créativité, vous pouvez créer une fonction :

mktouch() {
    if [ $# -lt 1 ]; then
        echo "Missing argument";
        return 1;
    fi

    for f in "$@"; do
        mkdir -p -- "$(dirname -- "$f")"
        touch -- "$f"
    done
}

Et puis utilisez-le comme n'importe quelle autre commande:

mktouch ./base/data/sounds/effects/camera_click.ogg ./some/other/file
Jonathon Reinhart
la source
Je l'ai changé pour l'utiliser &&- Comment ça?
Jonathon Reinhart
1
@ BЈовић Oui . (J'essaie de tester les choses avant de les publier.)
Jonathon Reinhart
2
@JonathonReinhart Etes-vous sûr de l'avoir testé? J'ai essayé supertouch "/tmp/abc/def ghi/jkl mno.txt"et cela a échoué. Toutes les commandes dirname, mkdiret toucha donné erros.
devnull
2
@devnull Apparemment pas assez bien. Merde vos espaces :-) Fixé.
Jonathon Reinhart
1
@JeremyIglehart j'aime ça. mktouchc'est.
Jonathon Reinhart
24

Faites-le avec / usr / bin / install:

install -D /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt

lorsque vous n'avez pas de fichier source:

install -D <(echo 1) /my/other/path/here/cpedthing.txt
Ivan Dives
la source
1
Je suis surpris que cet outil de gemme soit largement ignoré - man install - montrera que l'installation est une meilleure solution.
SC-SL
1
Vous pouvez également utiliser -D /dev/null, ce qui est plus facile à retenir pour moi.
wisbucky
14

Voici ce que je ferais:

mkdir -p /my/other/path/here && touch $_/cpredthing.txt

Ici, le $_est une variable qui représente le dernier argument de la commande précédente que nous avons exécutée en ligne.

Comme toujours, si vous voulez voir ce que pourrait être la sortie, vous pouvez la tester en utilisant la echocommande, comme ceci:

echo mkdir -p /code/temp/other/path/here && echo touch $_/cpredthing.txt

Quelles sorties comme:

mkdir -p /code/temp/other/path/here
touch /code/temp/other/path/here/cpredthing.txt

En prime, vous pouvez écrire plusieurs fichiers à la fois en utilisant l'extension d'accolades, par exemple:

mkdir -p /code/temp/other/path/here &&
touch $_/{cpredthing.txt,anotherfile,somescript.sh}

Encore une fois, totalement testable avec echo:

mkdir -p /code/temp/other/path/here
touch /code/temp/other/path/here/cpredthing.txt /code/temp/other/path/here/anotherfile /code/temp/other/path/here/somescript.sh
Sgnl
la source
13
#!/bin/sh
for f in "$@"; do mkdir -p "$(dirname "$f")"; done
touch "$@"
Javier
la source
1
Un utilisateur anonyme a suggéré (via edit) d'utiliser à la dirname -z "$@" | xargs -0 mkdir -pplace, pour des raisons de performance. (Arrêtez de vous cacher, et rejoignez, pour l'amour de Pete! ;-)
jpaugh
11

vous pouvez le faire en deux étapes:

mkdir -p /my/other/path/here/
touch /my/other/path/here/cpedthing.txt
Jörg Beyer
la source
2
if [ ! -d /my/other ]
then
   mkdir /my/other/path/here
   cp /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt
fi
Barun Parichha
la source
2

comme je l'ai vu et testé dans un forum unix, cela résout le problème

ptouch() {
    for p in "$@"; do
        _dir="$(dirname -- "$p")"
        [ -d "$_dir" ] || mkdir -p -- "$_dir"
    touch -- "$p"
    done
}
Fabian Rios
la source
1

pas besoin de if thendéclarations ... vous pouvez le faire sur une seule ligne usign;

mkdir -p /my/other/path/here;cp /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt

- ou sur deux lignes -

mkdir -p /my/other/path/here
cp /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt

- l' -perreur empêche les retours si le répertoire existe déjà (c'est ce que je suis venu chercher ici :))

tediffer3rd
la source
1

Dans le cas spécial (mais pas rare) où vous essayez de recréer la même hiérarchie de répertoires, cela cp --parentspeut être utile.

Par exemple, si /my/longcontient les fichiers source et my/otherexiste déjà, vous pouvez le faire:

cd /my/long
cp --parents path/here/thing.txt /my/other
Todd Owen
la source
-4

si vous voulez simple avec un seul extrait de paramètre:

rm -rf /abs/path/to/file;  #prevent cases when old file was a folder
mkdir -p /abs/path/to/file; #make it fist as a dir
rm -rf /abs/path/to/file; #remove the leaf of the dir preserving parents 
touch /abs/path/to/file; #create the actual file
étranger
la source
3
Si vous voulez simplement vous débarrasser du travail de ces dernières heures †, lancez avec gratitude quelques rm -rfcommandes. - † Autrement dit, des heures , en supposant que vous adhériez à une politique de contrôle / sauvegarde de version raisonnable ... sinon, cela pourrait prendre des mois.
gauche vers
1
rm -rfne doit jamais être suggéré sans explications et avertissements appropriés.
Mausy5043