GNU/Linux >> Tutoriels Linux >  >> Linux

Extension du chemin d'accès Bash/shell pour Mkdir, Touch, etc. ?

Donc, faire quelque chose comme ça dans bash et la plupart des autres shells ne fonctionneront pas pour créer plusieurs sous-répertoires ou fichiers dans des sous-répertoires…

mkdir */test
touch */hello.txt

Il existe bien sûr de nombreuses façons de le faire, ma préférée est d'utiliser find lorsque cela est possible plutôt que d'utiliser un for boucle, pour la lisibilité principalement.

Mais ma question est la suivante :pourquoi ce qui précède ne fonctionne-t-il pas ?
D'après ce que je comprends, c'est parce que le fichier/chemin de destination complet n'existe pas, mais c'est sûrement une bonne chose si j'essaie de mkdir ou touch . Je suis toujours passé à autre chose et je ne l'ai jamais vraiment remis en question.
Mais est-ce que quelqu'un a une explication décente pour cela qui m'aidera à comprendre une fois pour toutes ?

Réponse acceptée :

Le point qui vous manque peut-être - avec lequel beaucoup de gens ont des problèmes,
surtout s'ils ont de l'expérience avec d'autres systèmes d'exploitation avant de venir à *nix
- est que, dans de nombreux autres systèmes d'exploitation, les caractères génériques sur le ligne de commande sont normalement passés à la commande traiter comme bon lui semble. Par exemple, dans l'invite de commande Windows,

rename *.jpeg *.jpg

Alors que, dans *nix, afin de simplifier le travail
du ou des programmeurs des commandes individuelles (par exemple, mv ), les caractères génériques
(lorsqu'ils ne sont ni entre guillemets ni échappés) sont gérés par le shell,
d'une manière indépendante de l'interface et de la fonctionnalité
de la commande dont les caractères génériques sont les arguments.
La plupart des programmes qui prennent des noms de fichiers comme arguments de ligne de commande s'attendent à ce que ces fichiers existent
(oui, mkdir et touch sont des exceptions à cette règle,
tout comme mkfifo , mknod , et, dans une certaine mesure, cp , ln , mv , et rename;
et il y en a probablement d'autres),
il n'est donc pas vraiment logique que le shell étende les caractères génériques
aux noms de fichiers qui n'existent pas.
Et pour le shell (et, par là, je veux dire tous shell –
Bourne, bash, csh, fish, ksh, zsh, etc…) gérer les exceptions différemment
serait probablement trop compliqué.

Cela dit, il existe plusieurs façons d'obtenir un résultat comme ce que vous voulez.
Si vous savez à quoi va s'étendre le caractère générique,
et que ce n'est pas long, vous pouvez le générer avec l'expansion des accolades :

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

Une solution plus générale :

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

Gilles m'a aidé à trouver une autre façon
de le faire en bash.

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

Évidemment benbradley est juste un identifiant ici ; vous pouvez utiliser n'importe quel nom
(par exemple, n'importe quelle lettre).
Il m'a fallu quelques essais pour réussir, alors laissez-moi vous expliquer :

  • identifier=value crée une variable (scalaire) nommée identifier (si elle n'existe pas déjà) et attribue la valeur value à cela.
    Par exemple, G=Man .
    Vous pouvez référencer une variable scalaire avec $identifier;
    par exemple, $G , ou, plus sûrement, comme ${identifier} .
    Par exemple, $Gage et $Gilla peut être indéfini,
    mais ${G}age est Manage et ${G}illa est Manilla .
  • identifier=(value1 value2) crée une variable tableau nommée identifier (s'il n'existe pas déjà) et lui attribue les valeurs répertoriées.
    Par exemple,
    spectrum=(red orange yellow green blue indigo violet)

    ou

      all_text_files=(*.txt)

      $name fera référence au premier élément (et est donc assez inutile).
      Vous pouvez référencer un élément arbitraire comme ${name[subscript]};
      par exemple, ${spectrum[0]} est red et ${spectrum[4]} est blue .
      Et vous pouvez utiliser ${name[@]} et ${name[*]} pour référencer le tableau entier.

      Connexe :L'iPod touch a été volé et doit être localisé ?

      Alors, le voici en morceaux :

        "   ${   benbradley[@]   /   %   /   /test   }   "
        • ${parameter/pattern/string} développe le ${parameter} et remplace la correspondance la plus longue
          du pattern avec string .
        • Si pattern commence par # ,
          il doit correspondre au début de la valeur développée du parameter .
          Si pattern commence par % ,
          il doit correspondre à la fin de la valeur développée du parameter .
          En d'autres termes,
          %(the-rest_of_the_pattern)

          agit comme

            (the-rest_of_the_regex)$

            (oui, cela semble un peu en arrière).
            Donc un pattern c'est juste un % est comme une expression régulière qui est juste un $
            il correspond à la fin de la chaîne d'entrée (espace de recherche).

            • Et j'utilise une string de /test .
              Cela remplace donc la fin du paramètre par /test (c'est-à-dire qu'il ajoute /test au paramètre).
            • Une autre chose à propos du ${parameter/pattern/string} ce n'est pas intuitif, c'est qu'il toujours se termine par un } .
              Il n'est pas nécessaire, et ne peut pas , terminez par un troisième / .
              Par conséquent, un / dans string ne peut pas être interprété comme un délimiteur,
              et donc nous pouvons avoir une string de /test sans avoir besoin d'échapper le / .
            • Si parameter est une variable tableau
              indicée par @ ou * ,
              l'opération de substitution est appliquée tour à tour à chaque membre du tableau.
            • Lorsque vous référencez un tableau en tant que ${name[@]} (plutôt que ${name[*]} ) et placez les résultats entre guillemets,
              vous préservez l'intégrité des éléments du tableau
              (c'est-à-dire que vous préservez les espaces et autres caractères spéciaux)
              sans combiner les éléments séparés en un long mot.

            Linux
            1. Comment créer un environnement Shell propre pour une utilisation temporaire ?

            2. Mode IDE / Emacs pour les scripts Shell dans Bash/Sh, etc.

            3. Raccourci Shell/Bash pour renommer en bloc des fichiers dans un dossier

            4. Comment puis-je trouver de l'aide pour la commande de point `.` dans * nix ?

            5. #!/bin/sh vs #!/bin/bash pour une portabilité maximale

            Bash pour la boucle

            .bashrc contre .bash_profile

            Tutoriel de script Bash pour les débutants

            Tutoriel Bash Heredoc pour les débutants

            Quel est votre shell préféré pour le travail d'administrateur système ?

            Shell Scripting pour les débutants - Comment écrire des scripts Bash sous Linux