separador ejemplos campos cadena buscar linux awk

linux - ejemplos - Usando awk para imprimir todas las columnas desde la nth hasta la última



awk ejemplos (24)

¿Funcionaría esto?

awk ''{print substr($0,length($1)+1);}'' < file

Aunque deja algo de espacio en blanco al frente.

Esta línea funcionó hasta que tuve espacios en blanco en el segundo campo.

svn status | grep ''/!'' | gawk ''{print $2;}'' > removedProjs

¿hay alguna manera de que awk imprima todo en $ 2 o más? ($ 3, $ 4 ... hasta que no tengamos más columnas?)

Supongo que debería agregar que estoy haciendo esto en un entorno Windows con Cygwin.


Debido a una respuesta incorrecta con más votos con 340 votos, ¡acabo de perder 5 minutos de mi vida! ¿Alguien intentó esta respuesta antes de votar esto? Aparentemente no. Completamente inutil.

Tengo un registro donde después de $ 5 con una dirección IP puede haber más texto o no texto. Necesito todo, desde la dirección IP hasta el final de la línea, si hay algo después de $ 5. En mi caso, esto es realmente un programa awk, no un awk oneliner así que awk debe resolver el problema. Cuando intento eliminar los primeros 4 campos usando la respuesta más votada pero completamente errónea:

echo " 7 27.10.16. Thu 11:57:18 37.244.182.218" | awk ''{$1=$2=$3=$4=""; printf "[%s]/n", $0}''

escupe una respuesta incorrecta e inútil (agregué [..] para demostrar):

[ 37.244.182.218 one two three]

Incluso hay algunas sugerencias para combinar substr con esta respuesta incorrecta. Como esa complicación es una mejora.

En cambio, si las columnas tienen un ancho fijo hasta que se necesiten el punto de corte y awk, la respuesta correcta es:

echo " 7 27.10.16. Thu 11:57:18 37.244.182.218" | awk ''{printf "[%s]/n", substr($0,28)}''

que produce la salida deseada:

[37.244.182.218 one two three]


Esta función awk devuelve una subcadena de $0 que incluye campos de begin a end :

function fields(begin, end, b, e, p, i) { b = 0; e = 0; p = 0; for (i = 1; i <= NF; ++i) { if (begin == i) { b = p; } p += length($i); e = p; if (end == i) { break; } p += length(FS); } return substr($0, b + 1, e - b); }

Para obtener todo a partir del campo 3:

tail = fields(3);

Para obtener una sección de $0 que cubre los campos 3 a 5:

middle = fields(3, 5);

b, e, p, i sin sentido en la lista de parámetros de función es solo una forma awk de declarar variables locales.


Esto es lo que preferí de todas las recomendaciones:

Imprimiendo desde la sexta hasta la última columna.

ls -lthr | awk ''{out=$6; for(i=7;i<=NF;i++){out=out" "$i}; print out}''

o

ls -lthr | awk ''{ORS=" "; for(i=6;i<=NF;i++) print $i;print "/n"}''


Esto funcionaría si está utilizando Bash y podría usar tantos ''x'' como elementos que desee descartar e ignora múltiples espacios si no se escapan.

while read x b; do echo "$b"; done < filename


Esto me irritó tanto que me senté y escribí un analizador de especificación de campo similar a un cut , probado con GNU Awk 3.1.7.

Primero, cree un nuevo script de la biblioteca Awk llamado pfcut , por ejemplo,

sudo nano /usr/share/awk/pfcut

Luego, pegue en el script de abajo y guarde. Después de eso, así es como se ve el uso:

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source ''/^/ { pfcut("-4"); }'' t1 t2 t3 t4 $ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source ''/^/ { pfcut("2-"); }'' t2 t3 t4 t5 t6 t7 $ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source ''/^/ { pfcut("-2,4,6-"); }'' t1 t2 t4 t6 t7

Para evitar escribir todo eso, supongo que lo mejor que se puede hacer (ver de otro modo ¿ Cargar automáticamente una función de usuario al iniciar con awk? - Unix & Linux Stack Exchange ) es agregar un alias a ~/.bashrc ; por ejemplo con:

$ echo "alias awk-pfcut=''awk -f pfcut --source''" >> ~/.bashrc $ source ~/.bashrc # refresh bash aliases

... entonces puedes llamar:

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk-pfcut ''/^/ { pfcut("-2,4,6-"); }'' t1 t2 t4 t6 t7

Aquí está la fuente del script pfcut :

# pfcut - print fields like cut # # sdaau, GNU GPL # Nov, 2013 function spfcut(formatstring) { # parse format string numsplitscomma = split(formatstring, fsa, ","); numspecparts = 0; split("", parts); # clear/initialize array (for e.g. `tail` piping into `awk`) for(i=1;i<=numsplitscomma;i++) { commapart=fsa[i]; numsplitsminus = split(fsa[i], cpa, "-"); # assume here a range is always just two parts: "a-b" # also assume user has already sorted the ranges #print numsplitsminus, cpa[1], cpa[2]; # debug if(numsplitsminus==2) { if ((cpa[1]) == "") cpa[1] = 1; if ((cpa[2]) == "") cpa[2] = NF; for(j=cpa[1];j<=cpa[2];j++) { parts[numspecparts++] = j; } } else parts[numspecparts++] = commapart; } n=asort(parts); outs=""; for(i=1;i<=n;i++) { outs = outs sprintf("%s%s", $parts[i], (i==n)?"":OFS); #print(i, parts[i]); # debug } return outs; } function pfcut(formatstring) { print spfcut(formatstring); }


Hay una pregunta duplicada con una respuesta más simple usando corte:

svn status | grep ''/!'' | cut -d/ -f2-

-d especifica el delimitador (espacio) , -f especifica la lista de columnas (todas comienzan con la segunda)


Imprimiendo columnas comenzando desde el # 2 (la salida no tendrá ningún espacio al principio):

ls -l | awk ''{sub(/[^ ]+ /, ""); print $0}''


La mayoría de las soluciones con awk dejan un espacio. Las opciones aquí evitan ese problema.

Opción 1

Una solución de corte simple (funciona solo con delimitadores individuales):

command | cut -d'' '' -f3-

opcion 2

Forzar un awk re-calc a veces elimina el espacio inicial agregado (OFS) que queda al eliminar los primeros campos (funciona con algunas versiones de awk):

command | awk ''{ $1=$2="";$0=$0;} NF=NF''

Opcion 3

La impresión de cada campo formateado con printf le dará más control:

$ in='' 1 2 3 4 5 6 7 8 '' $ echo "$in"|awk -v n=2 ''{ for(i=n+1;i<=NF;i++) printf("%s%s",$i,i==NF?RS:OFS);}'' 3 4 5 6 7 8

Sin embargo, todas las respuestas anteriores cambian todos los FS repetidos entre campos a OFS. Vamos a construir un par de opciones que no hagan eso.

Opción 4 (recomendado)

Un bucle con sub para eliminar campos y delimitadores en la parte frontal.
Y usando el valor de FS en lugar de espacio (que podría ser cambiado).
Es más portátil y no activa un cambio de FS a OFS: NOTA: ^[FS]* es aceptar una entrada con espacios iniciales.

$ in='' 1 2 3 4 5 6 7 8 '' $ echo "$in" | awk ''{ n=2; a="^["FS"]*[^"FS"]+["FS"]+"; for(i=1;i<=n;i++) sub( a , "" , $0 ) } 1 '' 3 4 5 6 7 8

Opcion 5

Es muy posible crear una solución que no agregue espacios en blanco adicionales (iniciales o finales), y conservar los espacios en blanco existentes mediante la función gensub de GNU awk, ya que:

$ echo '' 1 2 3 4 5 6 7 8 '' | awk -v n=2 ''BEGIN{ a="^["FS"]*"; b="([^"FS"]+["FS"]+)"; c="{"n"}"; } { print(gensub(a""b""c,"",1)); }'' 3 4 5 6 7 8

También se puede usar para intercambiar un grupo de campos dado un recuento n :

$ echo '' 1 2 3 4 5 6 7 8 '' | awk -v n=2 ''BEGIN{ a="^["FS"]*"; b="([^"FS"]+["FS"]+)"; c="{"n"}"; } { d=gensub(a""b""c,"",1); e=gensub("^(.*)"d,"//1",1,$0); print("|"d"|","!"e"!"); }'' |3 4 5 6 7 8 | ! 1 2 !

Por supuesto, en tal caso, la OFS se utiliza para separar ambas partes de la línea, y el espacio en blanco al final de los campos todavía se imprime.

NOTA: [FS]* se utiliza para permitir espacios iniciales en la línea de entrada.


Los ejemplos de Awk parecen complejos aquí, aquí hay una simple sintaxis de shell Bash:

command | while read -a cols; do echo ${cols[@]:1}; done

Donde 1 es tu n ª columna contando desde 0.

Ejemplo

Dado este contenido de archivo ( in.txt ):

c1 c1 c2 c1 c2 c3 c1 c2 c3 c4 c1 c2 c3 c4 c5

Aquí está la salida:

$ while read -a cols; do echo ${cols[@]:1}; done < in.txt c2 c2 c3 c2 c3 c4 c2 c3 c4 c5


No estaba contento con ninguna de las soluciones awk presentadas aquí porque quería extraer las primeras columnas y luego imprimir el resto, así que me volví a perl . El siguiente código extrae las dos primeras columnas y muestra el resto tal como está:

echo -e "a b c d/te/t/tf g" | / perl -ne ''my @f = split //s+/, $_, 3; printf "first: %s second: %s rest: %s", @f;''

La ventaja en comparación con la solución perl de Chris Koknat es que realmente solo los primeros n elementos se separan de la cadena de entrada; el resto de la cadena no está dividida en absoluto y, por lo tanto, permanece completamente intacta. Mi ejemplo demuestra esto con una mezcla de espacios y pestañas.

Para cambiar la cantidad de columnas que deben extraerse, reemplace las 3 en el ejemplo con n + 1.


Perl:

@m=`ls -ltr dir | grep ^d | awk ''{print /$6,/$7,/$8,/$9}''`; foreach $i (@m) { print "$i/n"; }


Podría usar un bucle for para recorrer los campos de impresión $ 2 a $ NF (variable incorporada que representa el número de campos en la línea).

Editar: Dado que "imprimir" añade una nueva línea, querrá almacenar los resultados:

awk ''{out=""; for(i=2;i<=NF;i++){out=out" "$i}; print out}''

Alternativamente, use printf:

awk ''{for(i=2;i<=NF;i++){printf "%s ", $i}; printf "/n"}''


Quiero extender las respuestas propuestas a la situación en la que los campos están delimitados por posiblemente varios espacios en blanco , la razón por la que el OP no está utilizando el cut , supongo.

Sé que el OP preguntó sobre awk , pero un enfoque sed funcionaría aquí (por ejemplo, imprimiendo columnas del 5 al último):

  • enfoque puro sed

    sed -r ''s/^/s*(/S+/s+){4}//'' somefile

    Explicación:

    • s/// se utiliza la forma estándar para realizar la sustitución
    • ^/s* coincide con cualquier espacio en blanco consecutivo al principio de la línea
    • /S+/s+ significa una columna de datos (caracteres que no son espacios en blanco seguidos de caracteres en blanco)
    • (){4} significa que el patrón se repite 4 veces.
  • sed y corte

    sed -r ''s/^/s+//; s//s+//t/g'' somefile | cut -f5-

    simplemente reemplazando espacios en blanco consecutivos por una sola pestaña;

  • tr y cut: tr también se pueden usar para comprimir caracteres consecutivos con la opción -s .

    tr -s [:blank:] <somefile | cut -d'' '' -f5-


Si desea texto con formato, encadene sus comandos con eco y use $ 0 para imprimir el último campo.

Ejemplo:

for i in {8..11}; do s1="$i" s2="str$i" s3="str with spaces $i" echo -n "$s1 $s2" | awk ''{printf "|%3d|%6s",$1,$2}'' echo -en "$s3" | awk ''{printf "|%-19s|/n", $0}'' done

Huellas dactilares:

| 8| str8|str with spaces 8 | | 9| str9|str with spaces 9 | | 10| str10|str with spaces 10 | | 11| str11|str with spaces 11 |


Si necesita columnas específicas impresas con delimitador arbitrario:

awk ''{print $3 " " $4}''

col # 3 col # 4

awk ''{print $3 "anything" $4}''

col # 3anythingcol # 4

Entonces, si tiene espacios en blanco en una columna, serán dos columnas, pero puede conectarlo con cualquier delimitador o sin él.


Si no desea reformatear la parte de la línea que no corta, la mejor solución que se me ocurre está en mi respuesta en:

¿Cómo imprimir todas las columnas después de un número particular usando awk?

Corta lo que está antes del número de campo N dado, e imprime todo el resto de la línea, incluido el número de campo N y mantiene el espaciado original (no se vuelve a formatear). No importa si la cadena del campo aparece también en algún otro lugar de la línea.

Definir una función:

fromField () { awk -v m="/x01" -v N="$1" ''{$N=m$N; print substr($0,index($0,m)+1)}'' }

Y úsalo así:

$ echo " bat bi iru lau bost " | fromField 3 iru lau bost $ echo " bat bi iru lau bost " | fromField 2 bi iru lau bost

La salida lo mantiene todo, incluidos los espacios finales.

En tu caso particular:

svn status | grep ''/!'' | fromField 2 > removedProjs

Si su archivo / secuencia no contiene caracteres de nueva línea en el medio de las líneas (podría estar usando un separador de registros diferente), puede usar:

awk -v m="/x0a" -v N="3" ''{$N=m$N ;print substr($0, index($0,m)+1)}''

El primer caso fallará solo en archivos / transmisiones que contengan el número de caracteres hexadecimales raros 1


Solución de Perl:

perl -lane ''splice @F,0,1; print join " ",@F'' file

Estas opciones de línea de comandos se utilizan:

  • -n bucle alrededor de cada línea del archivo de entrada, no imprimir automáticamente cada línea

  • -l elimina las nuevas líneas antes de procesar, y las agrega de nuevo después

  • -a modo de división automática: divide las líneas de entrada en la matriz @F. Por defecto a dividir en espacios en blanco

  • -e ejecutar el codigo perl

splice @F,0,1 elimina limpiamente la columna 0 de la matriz @F

join " ",@F une los elementos de la matriz @F, utilizando un espacio entre cada elemento

Solución Python:

python -c "import sys;[sys.stdout.write('' ''.join(line.split()[1:]) + ''/n'') for line in sys.stdin]" < file


Yo personalmente probé todas las respuestas mencionadas anteriormente, pero la mayoría de ellas eran un poco complejas o simplemente no eran correctas. La forma más fácil de hacerlo desde mi punto de vista es:

awk -F" " ''{ for (i=4; i<=NF; i++) print $i }''

  1. Donde -F "" define el delimitador que debe utilizar awk. En mi caso es el espacio en blanco, que también es el delimitador predeterminado para awk. Esto significa que -F "" puede ser ignorado.

  2. Donde NF define el número total de campos / columnas. Por lo tanto, el bucle comenzará desde el cuarto campo hasta el último campo / columna.

  3. Donde $ N recupera el valor del campo Nth. Por lo tanto, imprimir $ i imprimirá el campo / columna actual según el recuento de bucles.


imprimirá todos menos la primera columna:

awk ''{$1=""; print $0}'' somefile

imprimirá todas menos dos primeras columnas:

awk ''{$1=$2=""; print $0}'' somefile


awk ''{ for(i=3; i<=NF; ++i) printf $i""FS; print "" }''

lauhub propuso esta solución correcta, simple y rápida here


awk ''{out=$2; for(i=3;i<=NF;i++){out=out" "$i}; print out}''

Mi respuesta se basa en la de VeeArr , pero noté que comenzó con un espacio en blanco antes de imprimir la segunda columna (y el resto). Como solo tengo 1 punto de reputación, no puedo comentarlo, así que aquí va como una nueva respuesta:

comience con "out" como la segunda columna y luego agregue todas las demás columnas (si existen). Esto va bien siempre y cuando haya una segunda columna.


echo "1 2 3 4 5 6" | awk ''{ $NF = ""; print $0}''

éste usa awk para imprimir todo excepto el último campo


ls -la | awk ''{o=$1" "$3; for (i=5; i<=NF; i++) o=o" "$i; print o }''

De esta respuesta no está mal pero el espacio natural se ha ido.
Por favor entonces compáralo con este:

ls -la | cut -d/ -f4-

Entonces verías la diferencia.

Incluso ls -la | awk ''{$1=$2=""; print}'' ls -la | awk ''{$1=$2=""; print}'' ls -la | awk ''{$1=$2=""; print}'' que se basa en la respuesta mejor votada hasta ahora, no conserva el formato.

Por lo tanto, usaría lo siguiente, y también permite columnas selectivas explícitas al principio:

ls -la | cut -d/ -f1,4-

Tenga en cuenta que cada espacio también cuenta para las columnas, por ejemplo, a continuación, las columnas 1 y 3 están vacías, 2 es INFO y 4 es:

$ echo " INFO 2014-10-11 10:16:19 main " | cut -d/ -f1,3 $ echo " INFO 2014-10-11 10:16:19 main " | cut -d/ -f2,4 INFO 2014-10-11 $