Unix: crea il percorso di cartelle e file


126

So che puoi fare mkdirper creare una directory e touchper creare un file, ma non c'è modo di fare entrambe le operazioni in una volta?

cioè se voglio fare quanto segue quando la cartella othernon esiste:

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

Errore:

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

Qualcuno ha escogitato una funzione come soluzione alternativa per questo?



Se è essenziale che la creazione del file e della sua directory sia atomica, dovresti scrivere un file system che offra questa operazione. Non è possibile con i file system Linux standard.
Peter G.

@toop Capisco che questa domanda sia vecchia di un anno e mezzo, ma di recente sono state unite diverse risposte. Se hai bisogno di questo tipo di cose molto spesso, potresti trovare utile la mia risposta . (Direi più utile della risposta accettata, ma non sto chiedendo un rappresentante qui :-))
Jonathon Reinhart


@tdammers Q: "Come faccio a fare X?" A: "Ecco come fare Y"
Henry Henrinson

Risposte:


140

Utilizzare &&per combinare due comandi in una riga della shell:

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

Nota: in precedenza ho consigliato l'uso di ;per separare i due comandi ma, come sottolineato da @trysis, è probabilmente meglio usarlo &&nella maggior parte delle situazioni perché in caso di COMMAND1errore COMMAND2non verrà eseguito neanche. (Altrimenti questo potrebbe portare a problemi che potresti non aspettarti.)


16
Probabilmente è meglio usare &&, come con ;, se il primo comando fallisce, il secondo comando verrà comunque eseguito (e fallirà anche, poiché quella directory non esiste ancora). Con &&se il primo comando fallisce, il secondo comando non viene eseguito.
trysis

12
Una scorciatoia per l'esempio di codice può essere: mkdir -p /my/other/path/here && touch $_/cpredthing.txt. Il si $_espande essenzialmente all '"ultimo argomento nell'ultimo comando eseguito".
Sgnl

4
@Sgnl la tua è senza dubbio la risposta corretta. Non è solo più pulito, è meno soggetto a errori.
Choylton B. Higginbottom

3
Vorrei davvero touchprendere un -pparametro come mkdirfa.
Ben174

86

Devi prima creare tutte le directory principali.

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

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

Se vuoi essere creativo, puoi creare una funzione :

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

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

E poi usalo come qualsiasi altro comando:

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

L'ho cambiato per usarlo &&- Come va?
Jonathon Reinhart

1
@ BЈовић . (Cerco di testare le cose prima di pubblicarle.)
Jonathon Reinhart

2
@JonathonReinhart Sei sicuro di averlo testato? Ho provato supertouch "/tmp/abc/def ghi/jkl mno.txt"e non è riuscito. Tutti i comandi dirname, mkdire touchha dato erros.
devnull

2
@devnull Apparentemente non abbastanza bene. Accidenti ai tuoi spazi :-) Risolto.
Jonathon Reinhart

1
@JeremyIglehart mi piace. mktouchè.
Jonathon Reinhart

24

Fallo con / usr / bin / install:

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

quando non hai un file sorgente:

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

1
Sono sorpreso che questo strumento gemma sia ampiamente ignorato - man install - mostrerà che install è una soluzione migliore.
SC-SL

1
Puoi anche usare -D /dev/null, che è più facile da ricordare per me.
wisbucky

14

Questo è quello che farei:

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

Qui, $_è una variabile che rappresenta l'ultimo argomento del comando precedente che abbiamo eseguito in linea.

Come sempre, se vuoi vedere quale potrebbe essere l'output, puoi testarlo usando il echocomando, in questo modo:

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

Che esce come:

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

Come bonus, puoi scrivere più file contemporaneamente usando l'espansione delle parentesi graffe, ad esempio:

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

Ancora una volta, totalmente testabile con 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 utente anonimo ha suggerito (tramite modifica) di utilizzare dirname -z "$@" | xargs -0 mkdir -pinvece, per il bene delle prestazioni. (Smettila di nasconderti e unisciti, per l'amor di Pete! ;-)
jpaugh

11

puoi farlo in due passaggi:

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

come ho visto e testato in un forum unix questo risolve il problema

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

1

non c'è bisogno di if thendichiarazioni ... puoi farlo su una sola riga usign;

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

- o su due righe -

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

- -pimpedisce che l'errore ritorni se la directory esiste già (che è quello che sono venuto qui a cercare :))


1

Nel caso speciale (ma non raro) in cui stai cercando di ricreare la stessa gerarchia di directory, cp --parentspuò essere utile.

Ad esempio, se /my/longcontiene i file di origine ed my/otheresiste già, puoi farlo:

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

-4

se vuoi semplice con solo 1 snippet di parametro:

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
Se vuoi semplicemente sbarazzarti del lavoro delle ultime ore †, getta con gratitudine alcuni rm -rfcomandi. - † Cioè, ore , supponendo che tu aderisca a una ragionevole politica di controllo della versione / backup ... altrimenti, potrebbero essere mesi.
sinistra intorno

1
rm -rfnon dovrebbe mai essere suggerito senza una corretta spiegazione e avvertenze.
Mausy5043
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.