:
es otro nombre para true
. Ambas son conchas incorporadas en bash, pero no hay /bin/:
, solo a /bin/true
. La redirección de salida provoca el shell al open(2)
archivo con O_CREAT|O_TRUNC
. Si no se escribe nada, permanece en longitud cero.
Poner esas dos piezas juntas :> file
es un modismo bastante común para truncar archivos. Sin embargo, la mayoría de la gente trataría de hacerlo menos extraño escribiendo : >file
.
Como me preguntaste en un comentario sobre la segunda línea, convertiré mis comentarios en una respuesta. (aunque no hiciste esto en tu pregunta).
La segunda línea es un bucle que lee líneas de otherfile
algunas variables con nombre. El cuerpo del bucle se usa echo
para imprimirlos con ;
separadores en lugar de cualquier espacio en blanco que tenían antes. file
se cierra y se vuelve a abrir (para agregar) cada iteración, porque la redirección está dentro del bucle. El uso while ...;do read -r ...;done <otherfile >file
sería menos difícil y evitaría la necesidad de truncar primero el archivo. read -r
no come \
como un personaje de escape.
El procesamiento de texto en bash es bastante lento. Parte de eso es inevitable: read
tiene que ir un byte a la vez (una read(2)
llamada al sistema por byte) para evitar sobrepasar el final de una línea. Sería mejor usar la herramienta adecuada para el trabajo:
awk -vOFS=';' '{ print $1, $2, $4, $5, $3 }' -- otherfile >file
--
significa que su script no se rompe si otherfile
se le llama algo tonto --version
.
Establecer el Separador de campo de salida en ;
significa que puede pasar varios campos como argumentos para imprimir. Shell read
asigna todo el resto de la línea con espacios en blanco a la última variable, pero no hay forma de decirle a awk que solo se divida en 5. Si eso es importante, tal vez solo siga usando un bucle bash, porque no es conveniente en awk. Perl lo hace fácil, ya que split
puede tomar un argumento de campos máximos, pero es mucho más lento para iniciar que awk.
En realidad, resultó no ser tan difícil, solo una expresión regular fea para escribir. Para obtener el resto de la línea en lugar de $5
en awk, recorrer los campos aún pierde su espacio en blanco original. Mi primera idea viable es usar gensub
en $0
(toda la línea) para eliminar los primeros 4 campos (es decir, sin espacio seguido de espacio), dejando todo lo demás:
awk -vOFS=';' '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1); print $1, $2, $4, tail, $3 }' -- otherfile >file
Lo hice bien en el primer intento, pero el hecho de que estaba impresionado conmigo mismo por eso dice algo sobre la legibilidad de ese código awk. >. <
Tenga en cuenta que es igual print
que antes, pero con tail
en lugar de $5
.
echo 'A B c DD e f g f' |
awk -vOFS=\; '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1);
print $1, $2, $4, tail, $3 }'
A;B;DD;e f g f;c
Esto sería más impresionante si pudiera copiar / pegar el literal y mostrar que apareció en la salida. Escriba uno en bash con ^ Q. ctrl-Q significa Citar la siguiente pulsación de tecla como un carácter literal, ya que la edición de línea al estilo de emacs de bash es la misma que la de emacs real para esto.
http://mywiki.wooledge.org/BashFAQ tiene algunas cosas útiles acerca de las secuencias de comandos de manera que no se rompan sin importar qué datos o nombres de archivos arrojes a la secuencia de comandos.
:>
que no es un solo operador. Puede ser más fácil de entender si lo lees como en su: > file
lugar.