¿Cómo hago una sustitución de `$0` pero guardo el valor anterior?

¿Cómo hago una sustitución de `$0` pero guardo el valor anterior?

Estoy intentando cambiar el nombre de todos los archivos que comienzan con "m" para que tengan el mismo nombre, excepto que se ha eliminado el primer carácter (o "m" en este caso).

Mi estrategia es:

  1. Enumere todos los archivos, conls
  2. Filtrar por los que quiero, conegrep
  3. Generar la cadena que no quiero al lado de la que quiero, separada por un espacio, con awk, por ejemplo,mfoo foo
  4. alimentar xargsamv mfoo foo

Algunas preguntas:

  • ¿Es esta una buena estrategia?
  • ¿Cuál es mejor?

Estoy atascado en el Paso 3. A continuación se muestra cómo abordé el problema.

Estoy trabajando en el siguiente directorio:

$ find .
.
./cat
./mbar
./mbaz
./mfoo

Puedo obtener rápidamente 1-2:

$ ls | egrep '^m'
mbar
mbaz
mfoo

El paso 3 es más difícil. Solía gsub​​​​generar la segunda cadena que quiero, pero no estoy seguro de cómo "pegarla con el valor original separado por un espacio":

$ ls | egrep '^m' | awk '{ gsub(/^./, ""); print }'
bar
baz
foo

El paso 4 tiene sentido para mí, aunque no estoy seguro de cómo terminar el paso 3, así que no puedo terminarlo todavía. A continuación se muestra un ejemplo de cómo creo que debería funcionar:

$ echo mfoo foo | xargs mv
$ find .
.
./cat
./foo
./mbar
./mbaz

Creo que estoy cerca. Sólo necesito descubrir cómo guardar el valor anterior e imprimirlo junto al valor gsubed. Probé el siguiente pequeño ejemplo pero no funciona:

$ echo mfoo | awk '
pipe quote> { old = $0 }
pipe quote> { new = gsub(/^./, "") }
pipe quote> { print $old " " $new }'
awk: illegal field $(mfoo), name "old"
 input record number 1, file
 source line number 4
  • ¿Cómo hago una sustitución $0pero guardo el valor anterior?
  • ¿Por qué recibo este error?

Respuesta1

Esto debería manejar toda la operación:

for file in m*; do mv "${file}" "${file#m}"; done

Antes de ejecutar eso, verifique las cosas primero con

for file in m*; do echo mv "${file}" "${file#m}"; done

Esto usa el m*glob para los pasos 1 y 2, luego ${file#m}(que elimina “m” del principio de ${file}) para el paso 3 y finalmente un bucle para el paso 4.

Para responder a su pregunta de AWK, puede hacerlo de esta manera:

echo mfoo | awk '{ print $0, substr($0, 2) }'

Las variables AWK no usan $, eso es solo para campos; de ahí viene tu error: AWK entiende $oldcomo “el valor del campo numerado según el valor de old”. También es más fácil de leer si colocas tus comandos en un solo bloque (suponiendo que tengan el mismo patrón). Arreglar tu guión te da

echo mfoo | awk '{ old = $0; gsub(/^./, ""); print old, $0 }'

Respuesta2

ls | egrep '^m' | awk '{ x=$0; gsub(/^./, ""); $0 = x " " $0 }1' | xargs -l -t mv

Posix-lyLa implementación se realiza a través de la -Lopción xargscomo:

ls | egrep '^m' | awk '{ x=$0; gsub(/^./, ""); $0 = x " " $0 }1' | xargs -L 1 -t mv

ls | egrep '^m' | awk '{ x=$0; gsub(/^./, ""); print x, $0 }' | xargs -L 1 -t mv

Basado en querespondíA su consulta anterior sobre xargs, podemos darle un buen uso a ese aprendizaje en este ejemplo.

Modifiqué ligeramente su awkcódigo: conserva la línea original ( $0) ya que la gsubfunción la golpeará. Luego juntamos lo antiguo y lo nuevo para obtener la línea que queremos enviar a xargsla que luego se invocará mvcon los argumentos correctos para efectuar el cambio de nombre.

Respuesta3

Una mejor estrategia es utilizar el renamecomando.

Tenga en cuenta que la sintaxis exacta de estos comandos es específica de la distribución; consulte la manpágina de su versión particular de la distribución. En Ubuntu, por ejemplo, que tiene una implementación de Perl rename, puedes usar una expresión regular:

rename -nono 's/^m//' m*

Nota: elimine la -nonobandera para realizar el cambio de nombre.

información relacionada