Wie erstelle ich ein Verzeichnis in allen Unterverzeichnissen?

34

Angenommen, ich habe eine Verzeichnisstruktur wie diese:

$ [~ / practice] ls
A B C D/

Jetzt möchte ich ein Verzeichnis tmp1in allen Unterverzeichnissen von anlegen practiceund mache folgendes:

$ [~ / practice] mkdir * / tmp1
mkdir: Verzeichnis kann nicht erstellt werden * / tmp1: Keine solche Datei oder kein solches Verzeichnis

Dann versuche ich den -pSchalter und ich endete mit einem Verzeichnis *mit einem Unterverzeichnistmp1

$ [~ / practice] mkdir -p * / tmp1

$ [~ / practice] ls
*/ A B C D/

Ich weiß, dass der -pSchalter verwendet wird, um mehrere nicht vorhandene Verzeichnisse zu erstellen. Ich dachte nur, es könnte helfen.

Wie erstelle ich tmp1in allen Unterverzeichnissen gleichzeitig?

Wenn dies geschehen kann, wie erweitere ich es zu schaffen \tmp1, \tmp2, \tmp3in \a, \bund \cauf einmal?

Edit: Ich vermisste zu erwähnen , dass die Verzeichnisse müssen nicht einfach und in Ordnung sein, wie a, b, cusw., und das Verzeichnis erstellt werden soll , nicht unbedingt wie tmp1, tmp2.

$ [~ / practice] ls
Hund / Katze / Ratte /

In ihnen möchte ich so etwas haben

$ [~ / practice] ls *
Hund:
rot blau/

Katze:
rot blau/

Ratte:
rot blau/
Animesh
quelle
1
In Anbetracht der Antwort von Christopher sollten Sie klären, ob "create \ tmp1, \ tmp2, \ tmp3 in \ a, \ b und \ c" insgesamt 3 oder 9 Unterverzeichnisse ergeben sollte.
Handarbeit
@manatwork: Das ist ein guter Punkt. Es sollten 9 Unterverzeichnisse erstellt werden.
Animesh
Dies ist meine Hilfe zur Lösung des Speicherplatzproblems im Namen des Verzeichnisses sudo find ./ -depth -type d -exec echo '"{} / RCS"' \;

Antworten:

44

Mit Globs :

for dir in */; do mkdir -- "$dir/tmp1"; done

HINWEIS

  • Ich behandle nur dirs (einschließlich Symlinks zu dirs) mit dem kleinen Hack, */als Glob zu verwenden
  • Wenn Sie mehrere Unterverzeichnisse gleichzeitig erstellen möchten:

    for dir in */; do mkdir -- "$dir"/{tmp1,foo,bar,qux}; done

Gilles Quenot
quelle
Kann ich for i in */; do mkdir "$i/itemone" "$i/itemtwo"; donefür mehrere, nicht in der Reihenfolge befindliche Verzeichnisnamen vorgehen?
Animesh
Ich habe das getestet und es ist sehr gut möglich. Vielen Dank.
Animesh
Siehe meinen bearbeiteten Beitrag
Gilles Quenot
1
Die Klammererweiterung wird nicht in Anführungszeichen ausgeführt.
Handarbeit
Ja, danke, Beitrag von Stephane Chazelas entsprechend bearbeitet ...
Gilles Quenot
10

[...] wie erweitere ich es, um gleichzeitig \ tmp1, \ tmp2, \ tmp3 in \ a, \ b und \ c zu erstellen?

 mkdir {a,b,c}/tmp{1,2,3}
Christopher
quelle
10

Mit GNU oder BSD * finden:

find -mindepth 1 -maxdepth 1 -type d -exec mkdir {}/newdir \;

oder mit Parametererweiterung:

dirs=(*/)
mkdir -- "${dirs[@]/%/newdir}"

* Beinhaltet OS X

Kojiro
quelle
2
Mit Standard-Suchsyntax:find . -name . -o -prune -type d -exec sh -c 'exec mkdir "$1/newdir"' sh {} \;
Stéphane Chazelas
1
Beachten Sie auch die Unterschiede zwischen den beiden Lösungen: Das erste enthält versteckte Verzeichnisse, das zweite fügt ein neues Verzeichnis in die Verzeichnisse ein, die durch einen Symlink im aktuellen Verzeichnis verknüpft sind.
Stéphane Chazelas
6

Off Topic, seitdem Sie es erwähnen bash, aber für das Protokoll, mit zsh, würden Sie Folgendes tun:

dirs=(*(/))
mkdir -- $^dirs/tmp1

$^varAktiviert die geschweifte Erweiterung für die Erweiterung des Arrays. Es erinnert an rc's^ Operator von und in rc(oder dessen Ableitung es), schreiben Sie es:

dirs=(*/)
mkdir -- $dirs^tmp1

Beachten Sie jedoch (und dasselbe gilt für die hier angegebenen bash-Lösungen), dass die rc-Lösung dirsauch symbolische Links zu Verzeichnissen enthält. In der zsh Lösung, ändern *(/)zu , *(-/)wenn Sie symbolische Links zu Verzeichnissen enthalten.

Stéphane Chazelas
quelle
+1 für deinen Punkt über Symlinks! Dieses Verhalten kann erwünscht sein, aber die Beschwerde von mkdir über das Erstellen eines doppelten Verzeichnisses kann mit dem -pFlag unterdrückt werden .
Kojiro
4

Übertragen Sie die Schleife über die übergeordneten Verzeichnisse:

for d in */; do mkdir "$d/red" "$d/blue"; done

Fügen Sie --danach hinzu, mkdirwenn Sie Verzeichnisse haben, deren Name mit beginnt -.

In zsh können Sie dies mit dem e Glob-Qualifikator in einem einzigen Befehl tun :

mkdir *(/e\''REPLY=($REPLY/{red,blue})'\')

Es ist jedoch schneller, dies als zwei Befehle einzugeben:

d=(*(/)); mkdir $^d/{red,blue}
Gilles 'SO - hör auf böse zu sein'
quelle
1
Auf einer Site, die als Referenz dienen soll, würde ich eher sagen " mkdir -- whateverund weglassen, -- wenn Sie beabsichtigen, die Erweiterung dessen, was möglicherweise als Option für den mkdirBefehl verwendet werden soll". Es hat keinen Sinn, --hier wegzulassen . Im Fall des OP ist dies möglicherweise kein Problem, im allgemeinen Fall jedoch. Ich denke, wir haben die Pflicht, hier die richtige und sichere Syntax beizubringen.
Stéphane Chazelas
@StephaneChazelas In einem Skriptkontext setze ich immer alle notwendigen --und Anführungszeichen und großen Fettwarnungen, wenn Zeilenumbrüche nicht unterstützt werden. In einem Befehlszeilenkontext zeige ich lieber die Schnellversion, die in der Praxis zuerst funktioniert, und die kugelsichere Version als Ergänzung.
Gilles 'SO - hör auf böse zu sein'
1

Das können Sie so machen:

mkdir {a,b,c,d}/tmp1
ДМИТРИЙ МАЛИКОВ
quelle
1
Was ist, wenn er 100 Verzeichnisse hat?
Bernhard
1

Variation über die Antwort von sputnick, die Nicht-Verzeichnisdateien vermeidet:

for x in *; do if [ -d "$x" ]; then mkdir "$x/tmp1"; fi; done
Goldlöckchen
quelle
Ich behandle nur dirs, das ist die ganze Magie ...
Gilles Quenot
cool, habe es;)
Goldlöckchen
2
Sollte das nicht sein if [ -d "$x" ];…?
Kojiro
Ja. Ich habe praktisch nie Leerzeichen in Dateinamen und neige dazu, das Zeug zu vergessen ...
Goldlöckchen
1

Dies ist eine gute Version des alten Unix-Masters (getestet auf FreeBSD 10.1), wenn Sie die Versionskontrolle (mit gesperrtem RCS-Check-in: ci -l mit einem kurzen Kommentar als ir: für die Erstveröffentlichung) Ihrer / etc / * config-Dateien durchführen möchten auf ~ / .his / etc

sudo rsync -av /etc/ ~/.his
sudo find -d ~/.his/etc -type d -exec echo '{}/RCS' \; | xargs sudo mkdir -p
sudo find -d ~/.his/etc \! -name "RCS" | xargs sudo ci -l -mir -t-ir
user108341
quelle
Ich
verstehe
1

Sollte sein \! Nennen Sie "RCS" und es funktioniert am besten beim ersten Einchecken.

sudo find ~ / .his / etc \! -name "RCS" -ls

sudo find -d ~ / .his / etc \! -name "RCS" | xargs sudo ci -l -mir -t-ir

Letzteres funktioniert auch sehr gut für den Test, indem der gesamte RCS-Inhalt nach dem Dateinamen gefiltert wird:

sudo find -d ~ / .his / etc -type f | grep -v RCS | xargs sudo ci -l -mir -t-ir

user108341
quelle
1

Das ist eine große Hilfe für mich. Ich musste eine Reihe von Unterverzeichnissen in mehreren Ordnern erstellen und so etwas wie:

!/bin/sh

cd /dest/cont

for dir in */*/; do
    mkdir -p -- $dir/{FB,Video,Audio,proj};
done

funktioniert hervorragend, außer wenn ein Leerzeichen auftritt. Gibt es eine Möglichkeit, Leerzeichen im */*/Teil der Argumente zu ignorieren ?

Johno
quelle