mkdir -p dla plików

24

mkdir -putworzy katalog; w razie potrzeby utworzy katalogi nadrzędne.

Czy istnieje podobne polecenie dla plików, które utworzy plik i katalogi nadrzędne w razie potrzeby?

Steven Penny
źródło
Nie jestem tego świadomy ... ale możesz po prostu zrobić mkdir -p / path / to / make && touch / path / to / file ... Który utworzyłby pusty plik w nowej strukturze katalogów, którą utworzyłeś w razie potrzeby.
1
@ Kansha łączy to z dirnamei basenamepotrzebujemy tylko jednego argumentu; zysk! :)
Tak, dobra rozmowa.

Odpowiedzi:

29

Instalator zrobi to, jeśli otrzyma plik źródłowy /dev/null. -DTeza mówi, aby utworzyć wszystkie katalogi nadrzędne:

anthony@Zia:~$ install -D /dev/null /tmp/a/b/c
anthony@Zia:~$ ls -l /tmp/a/b/c 
-rwxr-xr-x 1 anthony anthony 0 Jan 30 10:31 /tmp/a/b/c

Nie jestem pewien, czy to błąd, czy nie - jego zachowanie z plikami urządzeń nie jest wspomniane na stronie podręcznika. Możesz też po prostu nadać mu pusty plik (nowo utworzony mktemp, na przykład) jako źródło.

derobert
źródło
7

Nie, o ile mi wiadomo. Ale zawsze możesz używać mkdir -pi touchpo sobie:

f="/a/b/c.txt"
mkdir -p -- "${f%/*}" && touch -- "$f"
ldx
źródło
3

Często napotykałem tego rodzaju sytuacje, więc po prostu napisałem funkcję w swoim .bashrcpliku. To wygląda tak

function create() {
    arg=$1
    num_of_dirs=$(grep -o "/" <<< $arg | wc -l)
    make_dirs=$(echo $arg | cut -d / -f1-$num_of_dirs)
    mkdir -p $make_dirs && touch $arg
}

Więc kiedy chcę utworzyć plik w ścieżce nieistniejących katalogów, powiem

create what/is/it  # will create dirs 'what' and 'is', with file 'it' inside 'is'
ViKiG
źródło
1
Mój człowiek! - dziękuję, nazwałem to touchp, jakmkdir -p
ecoologic
0
dir=$(dirname "$f")
test -d $dir || mkdir -p "$dir"
Yordan Georgiev
źródło
3
To testnie jest potrzebne; mkdir -pnic nie robi, jeśli katalog już istnieje. Nawet nie zwraca błędu.
derobert
1
I oczywiście tworzy to tylko katalog.
CVn
0

Chciałem zasugerować, ponieważ utrzymuje ją w jednym wierszu, chociaż ustawienie zmiennej osobno pozwala ją zmienić i dość łatwo ponownie uruchomić polecenie z historii.

B="./make/this/path" && mkdir -p -- "$B" && touch -- "$B/file.txt"
Gilles „SO- przestań być zły”
źródło
0

Można to „sfałszować”.

Po pierwsze, kilka wymaganych teorii:

Rob Griffiths opublikował w 2007 r. Artykuł zatytułowany „ Łatwe tworzenie wielu nowych folderów” na Macworld.com, w którym omówił użycie xargspolecenia do odczytu listy plików do tworzenia katalogów mkdir.

xargsjest w stanie odwoływać się do placeholder( {}) z -Iflagą, która zawiera wartość każdego przekazanego argumentu xargs. Oto różnica między tą flagą a bez:

$ foo.txt bar.txt | xargs echo
$ => foo.txt bar.txt
$ foo.txt bar.txt | xargs -I {} echo {}
$ => foo.txt
$ => bar.txt

xargsjest również zdolny do uruchamiania dowolnych poleceń powłoki z sh -cflagą:

foo.txt bar.txt | xargs sh -c 'echo arbitrary command!'

Łączenie pojęć:

Możemy łączyć te pojęcia ze mkdir -pzamiast mkdiri koncepcji w @ldx „s odpowiedzi do produkcji to:

$ cat files.txt | xargs -I {} sh -c 'f="{}" && mkdir -p -- "${f%/*}" && touch -- "$f"'

To polecenie w zasadzie mapuje każdą nazwę pliku na rozdzielonej liniami listy plików, odcina część pliku, tworzy katalogi, mkdir -pa następnie touches nazwa pliku w odpowiednim katalogu.

Oto podział tego, co dzieje się w powyższym poleceniu:

Powiedzmy na przykład, że files.txtwygląda tak:

deeply/nested/foo/bar.txt
deeply/nested/baz/fiz.txt
  • cat files.txt produkuje deeply/nested/foo/bar.js deeply/nested/baz/fiz.txt
  • deeply/nested/foo/bar.js deeply/nested/baz/fiz.txt jest przesyłane do xargs
  • ponieważ użyliśmy -I {}, xargsprzetłumaczy każdy argument na własne polecenie, więc teraz mamy:
    • deeply/nested/foo/bar.txt
    • deeply/nested/baz/fiz.txt
  • następnie uruchamiamy polecenie powłoki, które wykorzystuje &&kombinator do grupowania 3 poleceń, które działają sekwencyjnie - pierwsze polecenie przechowuje plik w zmiennej środowiskowej (która jest ponownie używana przy następnym przejściu pliku) przy użyciu symbolu zastępczego, który wcześniej zarejestrowaliśmy, więc teraz mieć:
    • f=deeply/nested/foo/bar.txt
    • f=deeply/nested/baz/fiz.txt
  • mamy teraz zmienną, do której możemy przekazać mkdir -p, ale musimy wyciąć nazwę pliku. Prosty w użyciu '${f%/*}':
    • mkdir -p deeply/nested/foo/
    • mkdir -p deeply/nested/baz/
  • a następnie po prostu ponownie odwołujemy się do fzmiennej w całości, gdy touch:
    • touch deeply/nested/foo/bar.txt
    • touch deeply/nested/baz/fiz.txt
żyletka
źródło
2
Masz całe to wyjaśnienie tego, co jest w istocie cat files.txt | xargs -I {} sh -c 'f="{}" && mkdir -p -- "${f%/*}" && touch -- "$f"', co ma UUOC, a następnie podpowłokujesz na xargs, który podpowłoka wraca do powłoki, gdy while readpętla ma więcej sensu
Steven Penny
1
Przyznaję, że nie znam się na komendach * nix - nawet nie wiem, co to jest UUOC - ale nie rozumiem, jak to jest okropna odpowiedź. Jest badany, testowany i stanowi skuteczne rozwiązanie twojego pierwotnego pytania. Jest konstruktywny (w przeciwieństwie do twojego dość niegrzecznego komentarza). Proszę, jeśli uważasz, że zrobiłem tutaj coś nieodpowiedzialnego, czego nie powinienem, to opracuj dalej - wyjaśnij dlaczego . Nie dbam zbytnio o upartą debatę, która nie ma treści.
razorbeard
1
Mój ostatni komentarz wyjaśnia to doskonale. Całą odpowiedź można lepiej napisać jako while read f; do mkdir -p "$(dirname "$f")"; touch "$f"; done < files.txt. Mówi również fakt, że nie można przeprowadzić 10-sekundowego wyszukiwania UUOC w Internecie
Steven Penny