Unix - utwórz ścieżkę do folderów i plików


126

Wiem, że możesz mkdirutworzyć katalog i touchplik, ale czy nie ma sposobu, aby wykonać obie operacje za jednym razem?

tj. jeśli chcę wykonać poniższe czynności, gdy folder othernie istnieje:

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

Błąd:

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

Czy ktoś wymyślił funkcję jako obejście tego problemu?



Jeśli konieczne jest, aby tworzenie pliku i jego katalogu były atomowe, musiałbyś napisać system plików, który oferuje tę operację. Nie jest to możliwe w przypadku standardowych systemów plików Linux.
Peter G.

@toop Rozumiem, że to pytanie ma obecnie półtora roku, ale kilka odpowiedzi zostało ostatnio połączonych w to. Jeśli często potrzebujesz tego typu rzeczy, moja odpowiedź może Ci się przydać. (Argumentowałbym, że jest to bardziej przydatne niż zaakceptowana odpowiedź, ale nie błagam o przedstawiciela tutaj :-))
Jonathon Reinhart


@tdammers P: „Jak zrobić X?” O: „Oto jak to zrobić”
Henry Henrinson

Odpowiedzi:


140

Służy &&do łączenia dwóch poleceń w jednej linii powłoki:

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

Uwaga: Wcześniej ;zalecałem użycie do oddzielenia dwóch poleceń, ale jak wskazał @trysis, prawdopodobnie lepiej jest używać go &&w większości sytuacji, ponieważ w przypadku COMMAND1niepowodzenia COMMAND2również nie zostanie wykonany. (W przeciwnym razie może to prowadzić do problemów, których mógłbyś się nie spodziewać).


16
Prawdopodobnie lepiej jest użyć &&, tak jak w przypadku ;, gdy pierwsze polecenie zawiedzie, drugie polecenie nadal będzie działać (i również się nie powiedzie, ponieważ ten katalog jeszcze nie istnieje). Ze &&jeśli pierwsze polecenie zakończy się niepowodzeniem, druga komenda nie działa.
trysis

12
Krótkie cięcie na przykład kodu może być: mkdir -p /my/other/path/here && touch $_/cpredthing.txt. W $_rozszerza się zasadniczo do „ostatniej argumentem ostatniego wykonanego polecenia”.
Sgnl

4
@Sgnl yours to prawdopodobnie poprawna odpowiedź. Jest nie tylko czystszy, ale także mniej podatny na błędy.
Choylton B. Higginbottom

3
Naprawdę chciałbym touchmieć -ptaki parametr jak mkdirrobi.
Ben174

86

Najpierw musisz utworzyć wszystkie katalogi nadrzędne.

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

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

Jeśli chcesz być kreatywny, możesz stworzyć funkcję :

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

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

A następnie użyj go jak każdego innego polecenia:

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

Zmieniono to do użycia &&- jak to jest?
Jonathon Reinhart

1
@ BЈовић Yes . (Próbuję przetestować rzeczy, zanim je opublikuję.)
Jonathon Reinhart

2
@JonathonReinhart Czy na pewno to przetestowałeś? Próbowałem supertouch "/tmp/abc/def ghi/jkl mno.txt"i nie udało się. Wszystkie polecenia dirname, mkdiri touchdał erros.
devnull

2
@devnull Najwyraźniej nie wystarczająco dobrze. Cholera wasze przestrzenie :-) Naprawiono.
Jonathon Reinhart

1
@JeremyIglehart Podoba mi się. mktouchto jest.
Jonathon Reinhart

24

Zrób to za pomocą / usr / bin / install:

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

gdy nie masz pliku źródłowego:

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

1
Dziwię się, że to narzędzie klejnotów jest w dużej mierze ignorowane - instalacja man - pokaże, że instalacja jest lepszym rozwiązaniem.
SC-SL

1
Możesz także użyć -D /dev/null, co jest dla mnie łatwiejsze do zapamiętania.
wisbucky

14

Oto, co bym zrobił:

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

Tutaj $_jest zmienną, która reprezentuje ostatni argument poprzedniego polecenia, które wykonaliśmy w linii.

Jak zawsze, jeśli chcesz zobaczyć, jakie może być wyjście, możesz to przetestować za pomocą echopolecenia, na przykład:

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

Które wyjścia jako:

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

Jako bonus możesz napisać wiele plików naraz, używając rozszerzenia nawiasów klamrowych, na przykład:

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

Ponownie, całkowicie testowalne za pomocą 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
Anonimowy użytkownik zasugerował (poprzez edycję) użycie dirname -z "$@" | xargs -0 mkdir -pzamiast tego ze względu na wydajność. (Przestań się czaić i dołącz, na litość Pete'a! ;-)
jpaugh

11

możesz to zrobić w dwóch krokach:

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

jak widziałem i testowałem na forum unixowym, rozwiązuje to problem

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

1

nie potrzeba if theninstrukcji ... możesz to zrobić w jednym wierszu, używając znaku;

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

- lub w dwóch wierszach -

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

- -pbłąd zapobiega zwracaniu się, jeśli katalog już istnieje (właśnie tego szukałem :))


1

W specjalnym (ale nie rzadkim) przypadku, gdy próbujesz odtworzyć tę samą hierarchię katalogów, cp --parentsmoże być przydatne.

Na przykład, jeśli /my/longzawiera pliki źródłowe i my/otherjuż istnieje, możesz to zrobić:

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

-4

jeśli chcesz mieć prostotę z tylko jednym fragmentem parametru:

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
Jeśli chcesz po prostu pozbyć się pracy z ostatnich kilku godzin, z wdzięcznością rzuć kilka rm -rfkomend. - † To znaczy godzin , zakładając, że przestrzegasz rozsądnych zasad kontroli wersji / tworzenia kopii zapasowych ... w przeciwnym razie mogą to być miesiące.
lewej około

1
rm -rfnigdy nie należy sugerować bez odpowiedniego wyjaśnienia i ostrzeżeń.
Mausy5043
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.