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?



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


@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.)


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

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

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

13
#!/bin/sh
for f in "$@"; do mkdir -p "$(dirname "$f")"; done
touch "$@"

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

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

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
}

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 :))


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

-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

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.