Utilizando sed a masa renombrar archivos

Objetivo

Cambia estos nombres de archivo:

  • F00001-0708-RG-biasliuyda
  • F00001-0708-CS-akgdlaul
  • F00001-0708-VF-hioulgigl

a estos nombres de archivo:

  • F0001-0708-RG-biasliuyda
  • F0001-0708-CS-akgdlaul
  • F0001-0708-VF-hioulgigl

Código de Shell

Probar:

ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/' 

Actuar:

 ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/' | sh 

Mi pregunta

No entiendo el código sed. Entiendo lo que el comando de sustitución

 $ sed 's/something/mv' 

medio. Y entiendo algo de expresiones regulares. Pero no entiendo lo que está sucediendo aquí:

 \(.\).\(.*\) 

o aquí:

 & \1\2/ 

El primero, para mí, simplemente parece que significa: “un solo personaje, seguido de un solo personaje, seguido de cualquier secuencia de longitud de un solo personaje”, pero seguramente hay más que eso. En cuanto a la última parte:

 & \1\2/ 

No tengo idea. Realmente quiero entender este código. Por favor, ayúdenme, muchachos.

En primer lugar, debería decir que la forma más fácil de hacerlo es usar los comandos prename o rename.

En Ubuntu, OSX ( rename paquete Homebrew, paquete de MacPorts p5-file-rename ) u otros sistemas con perl rename (prename):

 rename s/0000/000/ F0000* 

o en sistemas con cambio de nombre de util-linux-ng, como RHEL:

 rename 0000 000 F0000* 

Eso es mucho más comprensible que el comando sed equivalente.

Pero en cuanto a la comprensión del comando sed, la página de manual de sed es útil. Si ejecuta man sed y busca & (usando el comando / para buscar), encontrará que es un carácter especial en s / foo / bar / replacements.

  s/regexp/replacement/ Attempt to match regexp against the pattern space. If success‐ ful, replace that portion matched with replacement. The replacement may contain the special character & to refer to that portion of the pattern space which matched, and the special escapes \1 through \9 to refer to the corresponding matching sub-expressions in the regexp. 

Por lo tanto, \(.\) Coincide con el primer carácter, al cual se puede hacer referencia mediante \1 . Entonces . coincide con el siguiente carácter, que siempre es 0. Entonces \(.*\) coincide con el rest del nombre del archivo, al cual se puede hacer referencia mediante \2 .

La cadena de reemplazo lo ensambla todo usando & (el nombre de archivo original) y \1\2 que es cada parte del nombre de archivo excepto el 2 ° carácter, que era un 0.

Esta es una forma bastante críptica de hacer esto, en mi humilde opinión. Si por alguna razón el comando rename no estuviera disponible y quisieras usar sed para hacer el cambio de nombre (¿o quizás estabas haciendo algo demasiado complejo para renombrar?), Ser más explícito en tu expresión regular lo haría mucho más legible. Quizás algo como:

 ls F00001-0708-*|sed 's/F0000\(.*\)/mv & F000\1/' | sh 

Poder ver lo que realmente está cambiando en s / search / replacement / lo hace mucho más legible. Tampoco seguirá chupando caracteres de tu nombre de archivo si accidentalmente lo ejecutas dos veces o algo así.