Entonces esto es para la tarea, pero no haré la pregunta específica de la tarea.
Necesito usar cabeza y cola para tomar diferentes conjuntos de líneas de un archivo. Entonces, como las líneas 6-11 y las líneas 19-24, guárdelas en otro archivo. Sé que puedo hacer esto usando append como
head -11 file|tail -6 > file1; head -24 file| tail -6 >> file1.
Pero no creo que debamos hacerlo.
¿Hay alguna forma específica de combinar los comandos head y tail y luego guardarlos en el archivo?
head
ytail
? Si es así, su solución es prácticamente lo mejor que puede hacer. Si tiene permiso para usar otros programas,sed
oawk
podría permitir soluciones más agradables (es decir, con menos invocaciones de procesos).>>
) encerrando los dos comandos de paréntesis, a reorientar su producción concatenada:(head -11 file | tail -6; head -24 file | tail -6) > file1
. Realmente se reduce a la preferencia personal, que es más agradable.Respuestas:
Puede hacerlo con
head
aritmética simple y básica, si agrupa comandos{ ... ; }
usando una construcción comodonde todos los comandos comparten la misma entrada (gracias @mikeserv ).
Obtener las líneas 6-11 y las líneas 19-24 es equivalente a:
Entonces, básicamente, ejecutarías:
fuente
Puede usar la
{ … }
construcción de agrupación para aplicar el operador de redirección a un comando compuesto.En lugar de duplicar las primeras líneas M + N y mantener solo la última N, puede omitir las primeras líneas M y duplicar la siguiente N. Esto es notablemente más rápido en archivos grandes . Tenga en cuenta que el
+N
argumento detail
no es el número de líneas a omitir, sino uno más: es el número de la primera línea a imprimir con líneas numeradas de 1.De cualquier manera, el archivo de salida solo se abre una vez, pero el archivo de entrada se recorre una vez para que cada fragmento se extraiga. ¿Qué hay de agrupar las entradas?
En general, esto no funciona. (Puede funcionar en algunos sistemas, al menos cuando la entrada es un archivo normal). ¿Por qué? Debido al búfer de entrada . La mayoría de los programas, incluidos
tail
, no leen su entrada byte a byte, sino algunos kilobytes a la vez, porque es más rápido. Entoncestail
lee unos kilobytes, salta un poco al principio, pasa un poco máshead
y se detiene, pero lo que se lee se lee y no está disponible para el siguiente comando.Otro enfoque es utilizar
head
canalizado a/dev/null
para omitir líneas.Una vez más, no se garantiza que funcione, debido al almacenamiento en búfer. Resulta que funciona con el
head
comando de GNU coreutils (el que se encuentra en los sistemas Linux no integrados), cuando la entrada es de un archivo normal. Esto se debe a que una vez que esta implementaciónhead
ha leído lo que quiere, establece la posición del archivo en el primer byte que no generó. Esto no funciona si la entrada es una tubería.Una forma más sencilla de imprimir varias secuencias de líneas desde un archivo es llamar a una herramienta más generalista como sed o awk . (Esto puede ser más lento, pero solo es importante para archivos extremadamente grandes).
fuente
Sé que dijiste que necesitas usar cabeza y cola, pero sed es definitivamente la herramienta más simple para el trabajo aquí.
Incluso puede construir los bloques en una cadena con algún otro proceso y ejecutarlo a través de sed.
-n niega la salida, luego especifica rangos para imprimir con p, con el primer y el último número del rango separados por una coma.
Dicho esto, puede hacer la agrupación de comandos que @don_crissti sugirió, o recorrer el archivo varias veces con la cabeza / cola agarrando un trozo de líneas cada vez que pasa.
Cuantas más líneas haya en un archivo y más bloques tenga, más eficiente será el sed.
fuente
Con
sed
usted podría hacer:... Posiblemente se podría tener una solución más eficiente
head
. Don ya ha demostrado cómo eso podría funcionar muy bien, pero también he estado jugando con eso. Algo que puede hacer para manejar este caso específico:... que llamar
head
4 veces escrito, ya sea aoutfile
o/dev/null
en función de si el valor de esa iteración de$n
un número par o impar.Para casos más generales, combiné esto con otras cosas que ya tenía:
Esto puede hacer lo tuyo como:
... que imprime ...
Espera que su primer argumento sea un recuento repetido con el prefijo a
-
, o, en su defecto, solo a-
. Si se proporciona un conteo, repetirá el patrón de línea dado en los siguientes argumentos tantas veces como se especifique y se detendrá tan pronto como lo haya hecho.Para cada argumento que sigue, interpretará un entero negativo para indicar un recuento de líneas en el que se debe escribir
/dev/null
y un entero positivo para indicar un recuento de líneas en el que se debe escribirstdout
.Entonces, en el ejemplo anterior, imprime las primeras 5 líneas en
/dev/null
, las siguientes 6 enstdout
, las siguientes 7 en/dev/null
otra vez y las siguientes 6 una vez más enstdout
. Después de haber alcanzado el último de sus argumentos y completar un ciclo completo a través del-1
recuento repetido, se cierra. Si el primer argumento hubiera sido-2
, habría repetido el proceso una vez más, o-
durante el mayor tiempo posible.Para cada ciclo arg, el
while
ciclo se procesa una vez. En la parte superior de cada bucle, la primera línea destdin
se lee en la variable de shell$l
. Esto es necesario porquewhile head </dev/null; do :; done
se repetirá indefinidamente,head
indica en su devolución cuando ha llegado al final del archivo. Por lo tanto, la verificación contra EOF está dedicadaread
yprintf
escribirá$l
más una nueva líneastdout
solo si el segundo argumento es un entero positivo.La
read
verificación complica un poco el ciclo porque inmediatamente después de que se llama a otro ciclo, unfor
ciclo que itera sobre args2-$#
como se representa en$n
cada iteración de suwhile
ciclo principal . Esto significa que para cada iteración, el primer argumento debe reducirse en uno del valor especificado en la línea de comando, pero todos los demás deben conservar sus valores originales, por lo que el valor del$_n
marcador var se resta de cada uno, pero solo tiene un valor valor mayor que 0 para el primer argumento.Eso constituye el bucle principal de la función, pero la mayor parte del código está en la parte superior y está destinado a permitir que la función almacene limpiamente incluso una tubería como entrada. Esto funciona llamando primero a un fondo
dd
para copiarlo en un archivo tmp en la salida en bloques de 4k por pieza. Luego, la función configura un ciclo de retención, que casi nunca debería completar ni un solo ciclo completo, solo para asegurarse de quedd
haya realizado al menos una sola escritura en el archivo antes de que la función reemplace su stdin con un descriptor de archivo vinculado al archivo tmp y luego inmediatamente desvincula el archivo conrm
. Esto permite que la función procese de manera confiable la secuencia sin requerir trampas o de otro modo para la limpieza: tan pronto como la función lo libere en el fd, el archivo tmp dejará de existir porque su único enlace de sistema de archivos con nombre ya se ha eliminado.fuente
Use una función bash como esta:
Esto es un poco exagerado en este caso, pero si tus filtros crecen, puede convertirse en una bendición.
fuente