Unix - Pfad der Ordner und Dateien erstellen


125

Ich weiß, dass Sie mkdirein Verzeichnis und toucheine Datei erstellen können, aber gibt es keine Möglichkeit, beide Vorgänge gleichzeitig auszuführen?

dh wenn ich das Folgende tun möchte, wenn der Ordner othernicht existiert:

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

Error:

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

Hat jemand eine Funktion als Problemumgehung dafür gefunden?



Wenn die Erstellung der Datei und ihres Verzeichnisses unbedingt atomar sein muss, müssen Sie ein Dateisystem schreiben, das diese Operation bietet. Mit den Standard-Linux-Dateisystemen ist dies nicht möglich.
Peter G.

@toop Ich verstehe, dass diese Frage jetzt anderthalb Jahre alt ist, aber kürzlich wurden mehrere Antworten darin zusammengeführt. Wenn Sie diese Art von Dingen sehr oft benötigen, finden Sie meine Antwort möglicherweise hilfreich. (Ich würde argumentieren, nützlicher als die akzeptierte Antwort, aber ich bitte hier nicht um Wiederholung :-))
Jonathon Reinhart


@tdammers F: "Wie mache ich X?" A: "Hier ist, wie man Y macht"
Henry Henrinson

Antworten:


139

Verwenden Sie &&diese Option , um zwei Befehle in einer Shell-Zeile zu kombinieren:

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

Hinweis: Bisher habe ich empfohlen Nutzung ;der beiden Befehle zu trennen , aber wie durch @trysis wies darauf hin , es ist wahrscheinlich besser, den Einsatz &&in den meisten Fällen , weil in dem Fall COMMAND1versagt COMMAND2wird auch nicht ausgeführt werden. (Andernfalls kann dies zu Problemen führen, die Sie möglicherweise nicht erwartet haben.)


16
Wahrscheinlich besser zu verwenden &&, da ;der zweite Befehl weiterhin ausgeführt wird, wenn der erste Befehl fehlschlägt (und auch fehlschlägt, da dieses Verzeichnis noch nicht vorhanden ist). Mit &&wenn der erste Befehl fehlschlägt, wird der zweite Befehl nicht ausgeführt.
Tryse

12
Eine Abkürzung für das Codebeispiel kann sein : mkdir -p /my/other/path/here && touch $_/cpredthing.txt. Das $_erweitert sich im Wesentlichen auf das "letzte Argument im zuletzt ausgeführten Befehl".
Sgnl

4
@Sgnl deine ist wohl die richtige Antwort. Es ist nicht nur sauberer, es ist auch weniger fehleranfällig.
Choylton B. Higginbottom

3
Ich wünschte wirklich, ich hätte toucheinen -pParameter wie mkdirdiesen genommen.
Ben174

86

Sie müssen zuerst alle übergeordneten Verzeichnisse erstellen.

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

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

Wenn Sie kreativ werden möchten, können Sie eine Funktion erstellen :

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

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

Und dann verwenden Sie es wie jeden anderen Befehl:

mktouch ./base/data/sounds/effects/camera_click.ogg ./some/other/file

Geändert, um zu verwenden &&- Wie ist das?
Jonathon Reinhart

1
@ BЈовић Ja . (Ich versuche Dinge zu testen, bevor ich sie
poste

2
@ JonathonReinhart Bist du sicher, dass du es getestet hast? Ich habe es versucht supertouch "/tmp/abc/def ghi/jkl mno.txt"und es ist fehlgeschlagen. Alle Befehle dirname, mkdirund touchgab erros.
devnull

2
@devnull Anscheinend nicht gut genug. Verdammt deine Räume :-) Behoben.
Jonathon Reinhart

1
@ JeremyIglehart Ich mag es. mktouches ist.
Jonathon Reinhart

24

Mach es mit / usr / bin / install:

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

Wenn Sie keine Quelldatei haben:

install -D <(echo 1) /my/other/path/here/cpedthing.txt

1
Ich bin überrascht, dass dieses Juwel-Tool weitgehend ignoriert wird - man install - wird zeigen, dass install eine bessere Lösung ist.
SC-SL

1
Sie können auch verwenden -D /dev/null, was für mich leichter zu merken ist.
wisbucky

14

Das würde ich tun:

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

Hier ist das $_eine Variable, die das letzte Argument für den vorherigen Befehl darstellt, den wir in Zeile ausgeführt haben.

Wie immer, wenn Sie sehen möchten, wie die Ausgabe echoaussehen könnte, können Sie sie mit dem folgenden Befehl testen :

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

Welche Ausgaben als:

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

Als Bonus können Sie mit der Klammererweiterung mehrere Dateien gleichzeitig schreiben, zum Beispiel:

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

Wieder völlig testbar mit 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
Ein anonymer Benutzer schlug (über die Bearbeitung) vor, dirname -z "$@" | xargs -0 mkdir -pstattdessen aus Gründen der Leistung zu verwenden. (Hör auf zu lauern und
mach

11

Sie können dies in zwei Schritten tun:

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

Wie ich in einem Unix-Forum gesehen und getestet habe, löst dies das Problem

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

1

Keine Notwendigkeit für if thenAnweisungen ... Sie können dies in einer einzelnen Zeile tun;

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

- oder in zwei Zeilen -

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

- Der -pverhindert, dass ein Fehler zurückkehrt, wenn das Verzeichnis bereits vorhanden ist (was ich hier gesucht habe :))


1

In dem speziellen (aber nicht ungewöhnlichen) Fall, in dem Sie versuchen, dieselbe Verzeichnishierarchie wiederherzustellen, cp --parentskann dies hilfreich sein.

Wenn Sie beispielsweise /my/longdie Quelldateien enthalten und my/otherbereits vorhanden sind, können Sie Folgendes tun:

cd /my/long
cp --parents path/here/thing.txt /my/other

-4

Wenn Sie einfach mit nur 1 Parameter-Snippet wollen:

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
Wenn Sie die Arbeit der letzten Stunden einfach loswerden möchten, werfen Sie dankbar einige rm -rfBefehle herum . - † Das heißt, Stunden , vorausgesetzt, Sie halten sich an eine vernünftige Versionskontroll- / Sicherungsrichtlinie ... andernfalls kann es durchaus Monate dauern .
links um

1
rm -rfsollte niemals ohne angemessene Erklärung und Warnungen vorgeschlagen werden.
Mausy5043
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.