GNU/Linux >> Tutoriales Linux >  >> Linux

¿Expansión de nombre de ruta de Bash/shell para Mkdir, Touch, etc.?

Entonces, hacer algo como esto en bash y la mayoría de los otros shells no funcionarán para crear múltiples subdirectorios o archivos dentro de subdirectorios...

mkdir */test
touch */hello.txt

Por supuesto, hay muchas formas de hacer esto, mi preferida es usar find cuando sea posible en lugar de usar un for loop, principalmente por legibilidad.

Pero mi pregunta es, ¿por qué lo anterior no funciona?
Por lo que entiendo, es porque la ruta/archivo de destino completo no existe, pero seguramente eso es algo bueno si estoy tratando de mkdir o touch . Siempre he seguido adelante y nunca lo cuestioné realmente.
Pero, ¿alguien tiene una explicación decente para esto que me ayude a entender de una vez por todas?

Respuesta aceptada:

El punto que puede estar pasando por alto, con el que muchas personas tienen problemas,
especialmente si tienen experiencia con otros sistemas operativos antes de llegar a *nix
, es que, en muchos otros sistemas operativos, los comodines en el línea de comando normalmente se pasan al comando para procesar como crea conveniente. Por ejemplo, en el símbolo del sistema de Windows,

rename *.jpeg *.jpg

Mientras que, en *nix, para simplificar el trabajo
de los programadores de los comandos individuales (por ejemplo, mv ), los comodines
(cuando no están entrecomillados ni escapados) son manejados por el shell,
de una manera que es independiente de la interfaz y la funcionalidad
del comando para el que los comodines son argumentos.
La mayoría de los programas que toman nombres de archivos como argumentos en la línea de comandos esperan que esos archivos existan
(sí, mkdir y touch son excepciones a esa regla,
al igual que mkfifo , mknod y, en parte, cp , ln , mv y rename;
y probablemente haya otros),
por lo que realmente no tiene sentido que el shell expanda los comodines
a nombres de archivos que no existen.
Y para el caparazón (y con eso me refiero a cada shell –
Bourne, bash, csh, fish, ksh, zsh, etc...) para manejar las excepciones de manera diferente
probablemente sería demasiado complicado.

Dicho esto, hay un par de maneras de obtener un resultado como el que desea.
Si sabe a qué se va a expandir el comodín,
y no es largo, puede generarlo con la expansión de llaves:

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

Una solución más general:

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

Gilles me ayudó a encontrar otra forma
de hacerlo en bash.

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

Obviamente benbradley es solo un identificador aquí; puede usar cualquier nombre
(por ejemplo, cualquier letra).
Me tomó un par de intentos hacerlo bien, así que déjame desglosarlo:

  • identifier=value crea una variable (escalar) llamada identifier (si aún no existe) y asigna el valor value lo.
    Por ejemplo, G=Man .
    Puede hacer referencia a una variable escalar con $identifier;
    por ejemplo, $G , o, más seguro, como ${identifier} .
    Por ejemplo, $Gage y $Gilla puede no estar definido,
    pero ${G}age es Manage y ${G}illa es Manilla .
  • identifier=(value1 value2) crea una variable de matriz llamada identifier (si aún no existe) y le asigna los valores enumerados.
    Por ejemplo,
    spectrum=(red orange yellow green blue indigo violet)

    o

      all_text_files=(*.txt)

      $name hará referencia al primer elemento (y por lo tanto es bastante inútil).
      Puede hacer referencia a un elemento arbitrario como ${name[subscript]};
      por ejemplo, ${spectrum[0]} es red y ${spectrum[4]} es blue .
      Y puedes usar ${name[@]} y ${name[*]} para hacer referencia a toda la matriz.

      Relacionado:¿El iPod touch fue robado y necesita ser localizado?

      Entonces, aquí está en pedazos:

        "   ${   benbradley[@]   /   %   /   /test   }   "
        • ${parameter/pattern/string} expande ${parameter} y reemplaza la coincidencia más larga
          de pattern con string .
        • Si pattern comienza con # ,
          debe coincidir con el principio del valor expandido del parameter .
          Si pattern comienza con % ,
          debe coincidir al final del valor expandido del parameter .
          En otras palabras,
          %(the-rest_of_the_pattern)

          actúa como

            (the-rest_of_the_regex)$

            (sí, eso parece un poco al revés).
            Así que un pattern eso es solo un % es como una expresión regular que es solo un $
            coincide con el final de la cadena de entrada (espacio de búsqueda).

            • Y estoy usando una string de /test .
              Entonces esto reemplaza el final del parámetro con /test (es decir, añade /test al parámetro).
            • Otra cosa sobre ${parameter/pattern/string} eso no es intuitivo es que siempre termina con un } .
              No es necesario y no puede , termina con un tercer / .
              Por lo tanto, un / en string no se puede interpretar como un delimitador,
              y por lo tanto podemos tener una string de /test sin necesidad de escapar del / .
            • Si parameter es una variable de matriz
              subíndice con @ o * ,
              la operación de sustitución se aplica a cada miembro de la matriz por turnos.
            • Cuando hace referencia a una matriz como ${name[@]} (en lugar de ${name[*]} ) y coloque los resultados entre comillas dobles,
              preserva la integridad de los elementos de la matriz
              (es decir, conserva los espacios y otros caracteres especiales en ellos)
              sin combinar los elementos separados en una palabra larga.

            Linux
            1. Personalización del shell Bash

            2. ¿Cómo crear un entorno de carcasa limpia para uso temporal?

            3. Cómo deshabilitar la finalización automática (finalización de pestañas) en bash Shell

            4. Modo IDE/Emacs para secuencias de comandos de Shell en Bash/Sh, etc.

            5. Acceso directo de Shell/Bash para cambiar el nombre de los archivos en una carpeta

            Golpe para bucle

            .bashrc frente a .bash_profile

            Tutorial de secuencias de comandos de Bash para principiantes

            Tutorial de Bash Heredoc para principiantes

            Shell Scripting para principiantes:cómo escribir Bash Scripts en Linux

            Script bash:usar el comando de script desde un script bash para iniciar sesión