Me he encontrado con una pregunta (sobre SO) donde OP tiene que hacer operaciones de edición y guardado en Input_file (s).
Sé que para un solo Input_file podríamos hacer lo siguiente:
awk '{print "test here..new line for saving.."}' Input_file > temp && mv temp Input_file
Ahora digamos que necesitamos hacer cambios en el mismo tipo de formato de archivos (suponga .txt aquí).
Lo que he intentado / pensado para este problema: su enfoque es pasar por un bucle for de archivos .txt y llamar a singleawk
es un proceso doloroso y NO recomendado, ya que desperdiciará ciclos de CPU innecesarios y para una mayor cantidad de archivos sería más lento.
Entonces, ¿qué se podría hacer aquí para realizar la edición in situ para múltiples archivos con un NO GNU awk
que no admite la opción in situ. También he revisado este hilo Guarde las modificaciones en el lugar con awk, pero no hay mucho para el vicio de NON GNU awk y el cambio de múltiples archivos in situ dentro de awk
sí mismo, ya que un no GNU awk no tendrá inplace
opción.
NOTA: ¿Por qué estoy agregandobash
etiquetas ya que, en mi parte de respuesta, he usado comandos bash para cambiar el nombre de los archivos temporales a sus nombres reales de Input_file para agregarlos?
EDITAR: Según el comentario de Ed sir agregando un ejemplo de muestras aquí, aunque el propósito del código de este hilo podría usarse también con la edición in situ con fines genéricos.
Muestra de archivos de entrada:
cat test1.txt
onetwo three
tets testtest
cat test2.txt
onetwo three
tets testtest
cat test3.txt
onetwo three
tets testtest
Muestra de salida esperada:
cat test1.txt
1
2
cat test2.txt
1
2
cat test3.txt
1
2
awk
(quizás en una subshell) o un{...}
grupo cerrado y luego escribir los resultados en el archivo de salida deseado (ya sea para cada archivo de entrada, o un archivo combinado para todos los archivos de entrada). Entonces, ¿simplemente redirige la salida de la subshell o grupo encerrado entre llaves al archivo actual en el que se está escribiendo? ¿Simplemente incluir una cadena de archivos de entrada siguiendo elawk
comando procesará secuencialmente todos los archivos (o algo similar)?awk {..} file1 .. fileX
escribir el archivo modificado como, por ejemplo,temp01
y en su próxima iteración mientras procesa el siguiente archivo, use amv -f tmp01 input01
para sobrescribir el archivo de entrada con los datos modificados; o (2) simplemente escriba un nuevo directorio./tmp/tmp01 ... ./tmp/tmp0X
durante la ejecución de laawk
secuencia de comandos y haga un seguimiento sobre los archivos del./tmp
directorio y, por ejemplo,mv -f "$i" "input_${i##*[^0-9]}"
(o cualquier expansión que necesite para reemplazar los archivos de entrada anteriores.awk
completar el código completo, la segunda opción es casi lo mismo que estoy usando en mi sugerencia. Le agradecería si pudiera hacer saber sus pensamientos sobre esa solución, señor.Respuestas:
Dado que el objetivo principal de este hilo es cómo hacer SAVE in-place en NON GNU,
awk
entonces publico primero su plantilla que ayudará a cualquier persona en cualquier tipo de requisito, necesitan agregar / agregarBEGIN
yEND
seccionar en su código manteniendo su BLOQUE principal según su requisito y debería hacer la edición in situ y luego:NOTA: Siguiente escribirá toda su salida en output_file, por lo que en caso de que desee imprimir algo en la salida estándar, solo agregue la
print...
declaración sin> (out)
seguir.Plantilla genérica:
Solución específica de la muestra proporcionada:
Se me ocurrió el siguiente enfoque dentro de
awk
sí mismo (para las muestras agregadas, el siguiente es mi enfoque para resolver esto y guardar la salida en Input_file)NOTA: esta es solo una prueba para guardar la salida editada en Input_file (s), uno podría usar su sección BEGIN, junto con su sección END en su programa, la sección principal debe cumplir con el requisito de la pregunta específica en sí.
Advertencia justa: también dado que este enfoque crea un nuevo archivo de salida temporal en la ruta, así que asegúrese de tener suficiente espacio en los sistemas, aunque en el resultado final esto mantendrá solo los Input_file (s) principales, pero durante las operaciones necesita espacio en el sistema / directorio
Lo siguiente es una prueba para el código anterior.
Ejecución del programa con un ejemplo: Supongamos que los siguientes son los
.txt
Input_file (s):Ahora cuando ejecutamos el siguiente código:
NOTA: Tengo lugar
ls -lhtr
en lasystem
sección intencionalmente para ver qué archivos de salida está creando (de manera temporal) porque más tarde los cambiará a su nombre real.Cuando hacemos una secuencia de comandos
ls -lhtr
posteriorawk
a la ejecución, solo podemos ver los.txt
archivos allí.Explicación: Agregar una explicación detallada del comando anterior aquí:
fuente
FNR==1
bloque, aún puede guardar los cambios en el lugar. Al igualawk 'FNR==1{system("rm " FILENAME)} {print "new lines" > FILENAME}' files...
. Esto no es confiable en absoluto (es probable que ocurra una pérdida completa de datos), pero aún así, en general funciona bien: DProbablemente iría con algo como esto si intentara hacer esto:
Hubiera preferido copiar el archivo original a la copia de seguridad primero y luego operar los cambios guardados en el original, pero hacerlo cambiaría el valor de la variable FILENAME para cada archivo de entrada que no es deseable.
Tenga en cuenta que si tuviera un archivo original llamado
whatever.bak
owhatever.new
en su directorio, los sobrescribiría con archivos temporales, por lo que también necesitaría agregar una prueba para eso. Una llamada paramktemp
obtener los nombres de los archivos temporales sería más sólida.Lo MUCHO más útil de tener en esta situación sería una herramienta que ejecute cualquier otro comando y realice la parte de edición "in situ", ya que podría usarse para proporcionar edición "in situ" para POSIX sed, awk, grep, tr, lo que sea y no requeriría que cambie la sintaxis de su script a
print > out
etc. cada vez que desee imprimir un valor. Un ejemplo simple y frágil:que usarías de la siguiente manera:
Un problema obvio con ese
inedit
script es la dificultad de identificar los archivos de entrada / salida por separado del comando cuando tiene múltiples archivos de entrada. El script anterior asume que todos los archivos de entrada aparecen como una lista al final del comando y el comando se ejecuta contra ellos uno a la vez, pero por supuesto eso significa que no puede usarlo para scripts que requieren 2 o más archivos en un tiempo, por ejemplo:o scripts que establecen variables entre archivos en la lista arg, por ejemplo:
Hacerlo más robusto se dejó como un ejercicio para el lector, pero mira la
xargs
sinopsis como un punto de partida de cómo un robustoinedit
necesitaría funcionar :-).fuente
La solución de shell es simple y probablemente lo suficientemente rápida:
Solo busque una solución diferente si ha demostrado de manera concluyente que esto es demasiado lento. Recuerde: la optimización prematura es la raíz de todo mal.
fuente