GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Bash/Shell-Pfadnamenerweiterung für Mkdir, Touch usw.?

Machen Sie also so etwas in bash und die meisten anderen Shells funktionieren nicht, um mehrere Unterverzeichnisse oder Dateien in Unterverzeichnissen zu erstellen …

mkdir */test
touch */hello.txt

Es gibt natürlich viele Möglichkeiten, dies tatsächlich zu tun, meine bevorzugte ist die Verwendung von find wenn möglich, anstatt einen for zu verwenden Schleife, hauptsächlich für die Lesbarkeit.

Aber meine Frage ist, warum das obige nicht funktioniert?
Soweit ich weiß, liegt es daran, dass die vollständige Zieldatei/der vollständige Zielpfad nicht existiert, aber das ist sicherlich eine gute Sache, wenn ich versuche, mkdir oder touch . Ich bin immer einfach weitergegangen und habe es nie wirklich in Frage gestellt.
Aber hat jemand eine anständige Erklärung dafür, die mir hilft, es ein für alle Mal zu verstehen?

Akzeptierte Antwort:

Der Punkt, den Sie möglicherweise übersehen – mit dem viele Leute Probleme haben,
insbesondere wenn sie Erfahrung mit anderen Betriebssystemen haben, bevor sie zu *nix
kommen – ist, dass in vielen anderen Betriebssystemen Platzhalter auf der Befehlszeile werden normalerweise an den Befehl übergeben nach eigenem Gutdünken verarbeiten. Beispielsweise in der Windows-Eingabeaufforderung

rename *.jpeg *.jpg

Wohingegen in *nix, um die Arbeit
des/der Programmierer(s) der einzelnen Befehle zu vereinfachen (z.B. mv ), Wildcards
(wenn sie nicht in Anführungszeichen oder Escapezeichen gesetzt sind) werden von der Shell behandelt,
in einer Weise, die unabhängig von der Schnittstelle und Funktionalität
des Befehls ist, für den die Wildcards Argumente sind.
Die meisten Programme, die Dateinamen als Befehlszeilenargumente verwenden, erwarten, dass diese Dateien existieren
(ja, mkdir und touch sind Ausnahmen von dieser Regel,
ebenso wie mkfifo , mknod , und teilweise cp , ln , mv , und rename;
und wahrscheinlich gibt es noch andere),
also macht es für die Shell keinen Sinn, Platzhalter
zu Namen für nicht existierende Dateien zu erweitern.
Und für die Shell (und damit meine ich jeden Shell –
Bourne, bash, csh, fish, ksh, zsh, etc…), die Ausnahmen anders zu handhaben
wäre wahrscheinlich zu umständlich.

Das heißt, es gibt ein paar Möglichkeiten, um ein Ergebnis zu erzielen, das Ihren Wünschen entspricht.
Wenn Sie wissen, worauf der Platzhalter erweitert wird,
und es nicht lange dauert, können Sie ihn mit der geschweiften Erweiterung generieren:

touch {red,orange,yellow,green,blue,indigo,violet}/rgb.txt

Eine allgemeinere Lösung:

sh -c 'for arg do mkdir -- "$arg"/test; done' -- *

Gilles hat mir geholfen, einen anderen Weg
in Bash zu finden.

benbradley=(*)
mkdir "${benbradley[@]/%//test}"

Offensichtlich benbradley ist hier nur eine Kennung; Sie können einen beliebigen Namen
verwenden (z. B. einen einzelnen Buchstaben).
Ich habe ein paar Versuche gebraucht, um das richtig hinzubekommen, also lassen Sie es mich aufschlüsseln:

  • identifier=value erstellt eine (skalare) Variable namens identifier (sofern noch nicht vorhanden) und weist den Wert value dazu.
    Zum Beispiel G=Man .
    Sie können eine skalare Variable mit $identifier;
    zum Beispiel $G , oder sicherer als ${identifier} .
    Zum Beispiel $Gage und $Gilla kann undefiniert sein,
    aber ${G}age ist Manage und ${G}illa ist Manilla .
  • identifier=(value1 value2) erstellt eine Array-Variable mit dem Namen identifier (sofern noch nicht vorhanden) und weist ihm die aufgelisteten Werte zu.
    Zum Beispiel
    spectrum=(red orange yellow green blue indigo violet)

    oder

      all_text_files=(*.txt)

      $name wird auf das erste Element verweisen (und ist daher ziemlich nutzlos).
      Sie können auf ein beliebiges Element als ${name[subscript]};
      zum Beispiel ${spectrum[0]} ist red und ${spectrum[4]} ist blue .
      Und Sie können ${name[@]} und ${name[*]} um auf das gesamte Array zu verweisen.

      Verwandte Themen:Der iPod touch wurde gestohlen und muss geortet werden?

      Also, hier ist es in Stücken:

        "   ${   benbradley[@]   /   %   /   /test   }   "
        • ${parameter/pattern/string} erweitert ${parameter} und ersetzt die längste Übereinstimmung
          von pattern mit string .
        • Wenn pattern beginnt mit # ,
          muss am Anfang des erweiterten Werts von parameter .
          Wenn pattern beginnt mit % ,
          muss am Ende des erweiterten Werts von parameter .
          Mit anderen Worten
          %(the-rest_of_the_pattern)

          verhält sich wie

            (the-rest_of_the_regex)$

            (ja, das scheint ein wenig rückständig).
            Also ein pattern das ist nur ein % ist wie ein regulärer Ausdruck, der nur ein $ ist –
            entspricht dem Ende der Eingabezeichenfolge (Suchraum).

            • Und ich verwende einen string von /test .
              Das ersetzt also das Ende des Parameters durch /test (d. h. es wird /test angehängt zum Parameter).
            • Noch etwas zu ${parameter/pattern/string} nicht intuitiv ist, dass es immer ist endet mit einem } .
              Es muss nicht und kann nicht , enden mit einem dritten / .
              Also ein / in string kann nicht als Trennzeichen interpretiert werden,
              und daher können wir einen string haben von /test ohne dass / maskiert werden muss .
            • Wenn parameter ist eine Array-Variable
              , die mit @ tiefgestellt ist oder * ,
              wird die Substitutionsoperation der Reihe nach auf jedes Mitglied des Arrays angewendet.
            • Wenn Sie auf ein Array als ${name[@]} (anstelle von ${name[*]} ) und setzen Sie die Ergebnisse in doppelte Anführungszeichen,
              bewahren Sie die Integrität der Elemente des Arrays
              (d. h. Sie behalten Leerzeichen und andere Sonderzeichen darin bei)
              ohne die einzelnen Elemente zu kombinieren ein langes Wort.

            Linux
            1. Die Begründung dafür, dass die Bash-Shell Sie nicht vor arithmetischem Überlauf usw. warnt?

            2. 12 Bash-For-Loop-Beispiele für Ihr Linux-Shell-Scripting

            3. So deaktivieren Sie die automatische Vervollständigung (Tab-Vervollständigung) in der Bash-Shell

            4. Shell/Bash-Verknüpfung zum Massenumbenennen von Dateien in einem Ordner

            5. Bash-Shell-Skript - Suchen Sie nach einem Flag und holen Sie sich seinen Wert

            Bash für Schleife

            .bashrc vs. .bash_profile

            Bash-Scripting-Tutorial für Anfänger

            Bash Heredoc-Tutorial für Anfänger

            Was ist Ihre Lieblings-Shell für die Arbeit als Systemadministrator?

            Shell-Scripting für Anfänger – So schreiben Sie Bash-Scripts unter Linux