@Jefromi: cuttampoco tiene expresiones regulares antes de las {}acciones, y luego es mucho más tonto con los delimitadores de campo (¿número variable de espacios?), Y debe especificarlos manualmente. Creo que el OP quería escuchar sobre algún shift Ncomando, que no existe. El más cercano es $1="";$2="";(...);print}, pero en mi caso deja algunos espacios iniciales (probablemente separadores).
Tomasz Gandor
Respuestas:
50
Una solución que no agrega espacios en blanco adicionales al principio o al final :
La respuesta de EdMorton no funcionó para mí (bash 4.1.2 (1) -release, GNU Awk 3.1.7 o bash 3.2.25 (1) -release, GNU Awk 3.1.5) pero encontré aquí otra forma:echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch
1
@elysch no, eso no funcionará en general, simplemente parece funcionar dados algunos valores de entrada específicos. Vea el comentario que agregué debajo de su comentario debajo de mi respuesta.
Ed Morton
1
Hola @fedorqui. Mi respuesta es la primera. En mi respuesta original, estaba explicando por qué la otra respuesta no era correcta (espacios en blanco adicionales al principio o al final). Algunas personas han propuesto mejoras en los comentarios. Le hemos pedido al OP que elija una respuesta más correcta y él / ella ha seleccionado la mía. Después de que algunos otros contribuyentes hayan editado mi respuesta para hacer referencia a esa respuesta (consulte el historial). ¿Está claro para ti? ¿Qué me aconseja para mejorar la comprensibilidad de mi respuesta? Saludos ;-)
olibre
1
Tiene toda la razón y lamento mucho mi malentendido. Hice una lectura rápida de la respuesta y no me di cuenta de su respuesta original (sí, leí demasiado rápido). +1 para la respuesta en sí usando el buen truco para hacer un bucle hasta NF-1 y luego imprimir el último elemento para evitar el espacio en blanco adicional. ¡Y lo siento de nuevo! (Eliminaré mi comentario en un día o dos, para evitar malentendidos de futuros lectores).
fedorqui 'SO deja de dañar'
1
Usaría algún tipo de encabezado: <su respuesta> y luego una regla horizontal seguida de un título grande "comparación de las otras respuestas". De lo contrario, mueva esta comparación a otra respuesta, ya que al parecer la gente tiende a preferir respuestas cortas en una visión "dame mi código":)
probablemente sea mejor utilizar "NF" que "13" en el último ejemplo.
glenn jackman
2
2 escenario que corresponde a OP decidir. si 13 es el último campo, usar NF está bien. De lo contrario, usar 13 es apropiado.
ghostdog74
3
2nd necesita eliminar 3 copias de OFS desde el comienzo de $ 0. Tercero sería mejor con printf "%s ",$i, ya que no sabes si $ipodría contener %so algo similar. Pero eso imprimiría un espacio extra al final.
Esto es bueno por lo dinámico que es. Puede agregar columnas al final y no reescribir sus scripts.
MinceMan
1
Esto demuestra el problema exacto con el que la pregunta está tratando de resolver, simplemente haga lo contrario. ¿Qué pasa con la impresión del campo 100? Tenga en cuenta que debe mencionar que no se ocupa de NFlo que deja el liderazgo OFS.
Chris Seymour
24
La forma correcta de hacer esto es con un intervalo RE porque le permite simplemente indicar cuántos campos omitir y conserva el espacio entre campos para los campos restantes.
por ejemplo, para omitir los primeros 3 campos sin afectar el espacio entre los campos restantes, dado el formato de entrada que parece que estamos discutiendo en esta pregunta, es simplemente:
Si tiene un FS que es un RE que no puede negar en un conjunto de caracteres, puede convertirlo a un solo carácter primero (RS es ideal si es un solo carácter, ya que un RS NO PUEDE aparecer dentro de un campo, de lo contrario, considere SUBSEP), luego aplique la sustitución del intervalo RE, luego conviértalo al OFS. por ejemplo, si las cadenas de "." separan los campos:
Entonces tiene el mismo problema que con todas las soluciones basadas en bucles que reasignan los campos: los FS se convierten en OFS. Si eso es un problema, necesita buscar en la función patsplit () de GNU awks.
No funcionó para mí (bash 4.1.2 (1) -release, GNU Awk 3.1.7 o bash 3.2.25 (1) -release, GNU Awk 3.1.5) pero encontré aquí de otra manera:echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch
2
No, eso fallará si $ 1 o $ 2 contienen la cadena en la que se establece $ 3. Pruebe, por ejemplo, echo ' That is a test' | awk '{print substr($0, index($0,$3))}'y encontrará que el avalor de $ 3 coincide con el ainterior Thatde $ 1. En una versión muy antigua de gawk como la que tiene, debe habilitar los intervalos RE con la bandera --re-interval.
Ed Morton
2
Tienes razón, no me di cuenta. Por cierto, realmente agradezco tu comentario. Muchas veces quise usar una expresión regular con "{}" para especificar el número de elementos y nunca vi "--re-interval" en el man. +1 para ti.
elysch
1
1es una condición verdadera y por lo tanto invoca la acción awk predeterminada de imprimir el registro actual.
Ed Morton
1
No sé lo canónico que es, pero agregué una respuesta ahora.
Ed Morton
10
Prácticamente todas las respuestas actualmente agregan espacios iniciales, espacios finales o algún otro problema de separador. Para seleccionar desde el cuarto campo donde el separador es un espacio en blanco y el separador de salida es un espacio único, el uso awksería:
O para ponerlos en la misma línea, asigne $ 3 a $ 1, etc. y luego cambie NF al número correcto de campos. echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) $(i-2)=$i; NF=NF-2; print $0 }'
larsr
Hola @larsr. Su línea de comando propuesta es la única respuesta correcta. Todas las demás respuestas agregan espacios adicionales (iniciales o finales). Por favor publique su línea de comando dentro de una nueva respuesta, la votaré ;-)
olibre
1
Hola @sudo_O, estaba hablando con @larsr, sobre la línea de comando que propuso en su comentario. Pasé unos cinco minutos antes de descubrir el quiproco (malentendido). Estoy de acuerdo, la respuesta de @Vetsin inserta nuevas líneas ( ORS) entre los campos. Bravo por tu iniciativa (me gusta tu respuesta). Saludos
olibre
3
Otra forma de evitar el uso de la declaración de impresión:
$ awk '{$1=$2=$3=""}sub("^"FS"*","")' file
En awk, cuando una condición es verdadera, la impresión es la acción predeterminada.
+1 para la solución similar ... Pero esto puede tener problemas de rendimiento si filees grande (> 10-30 KB). Para archivos grandes, la awksolución funciona mejor.
TrueY
3
Las opciones 1 a 3 tienen problemas con varios espacios en blanco (pero son simples). Esa es la razón para desarrollar las opciones 4 y 5, que procesan múltiples espacios en blanco sin problemas. Por supuesto, si se utilizan las opciones 4 o 5 con n=0ambas, se conservarán los espacios en blanco iniciales, lo que n=0significa que no habrá división.
Opción 1
Una solución de corte simple (funciona con delimitadores simples):
$ echo '1 2 3 4 5 6 7 8'| cut -d' '-f4-45678
opcion 2
Forzar una recalculación de awk a veces resuelve el problema (funciona con algunas versiones de awk) de espacios iniciales agregados:
NOTA: El "^ [" FS "] *" es para aceptar una entrada con espacios iniciales.
Opcion 5
Es muy posible construir una solución que no agregue espacios en blanco adicionales al principio o al final, y preservar los espacios en blanco existentes usando la función gensubde GNU awk, como esta:
Hola BZ Tu respuesta es agradable. Pero la Opción 3 no funciona en cadenas que comienzan con un espacio (p " 1 2 3 4 5 6 7 8 ". Ej .). La opción 4 es buena, pero deja un espacio inicial usando una cadena que comience con un espacio. ¿Crees que esto se puede arreglar? Puede usar el comando echo " 1 2 3 4 5 6 7 8 " | your awk script | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'para verificar los espacios
iniciales
Hola @olibre. Que la opción 3 falle con espacios en blanco es la razón para desarrollar las opciones 4 y 5. La opción 4 solo deja un espacio inicial si la entrada lo tiene y n se establece en 0 (n = 0). Creo que es la respuesta correcta cuando no hay una selección de campos (nada que arreglar en mi opinión). Salud.
Todo bien. Gracias por la información adicional :-) Por favor mejore su respuesta proporcionando esta información adicional :-) Saludos
olibre
Perfecto :-) Qué lástima que su usuario esté deshabilitado :-(
olibre
1
Cut tiene una marca --complement que hace que sea fácil (y rápido) eliminar columnas. La sintaxis resultante es análoga a lo que desea hacer, lo que hace que la solución sea más fácil de leer / comprender. El complemento también funciona para el caso en el que desee eliminar columnas no contiguas.
¿La edición anterior ayuda a comprender? El punto es utilizar la bandera de corte complementaria. La solución debe ser una implementación más rápida y concisa que las soluciones basadas en AWK o perl. Además, se pueden cortar columnas arbitrarias.
Michael Back
1
Solución Perl que no agrega espacios en blanco iniciales o finales:
Como me molestó la primera respuesta altamente votada pero incorrecta, encontré suficiente para escribir una respuesta allí, y aquí las respuestas incorrectas están marcadas como tales, aquí está mi parte. No me gustan las soluciones propuestas, ya que no veo ninguna razón para hacer que la respuesta sea tan compleja.
Tengo un registro donde después de $ 5 con una dirección IP puede haber más texto o ningún texto. Necesito todo, desde la dirección IP hasta el final de la línea, en caso de que haya algo después de $ 5. En mi caso, esto es realmente dentro de un programa awk, no un delineador awk, por lo que awk debe resolver el problema. Cuando trato de eliminar los primeros 4 campos usando la respuesta antigua, bonita y con más votos positivos, pero completamente incorrecta:
echo " 7 27.10.16. Thu 11:57:18 37.244.182.218 one two three"| 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]
En cambio, si las columnas tienen un ancho fijo hasta que se necesitan el punto de corte y awk, la respuesta correcta y bastante simple es:
echo " 7 27.10.16. Thu 11:57:18 37.244.182.218 one two three"| awk '{printf "[%s]\n", substr($0,28)}'
Las %-5salinea el resultado como columnas de 5 caracteres de ancho; si esto no es suficiente, aumente el número o use %s(con un espacio) en su lugar si no le importa la alineación.
Solución AWK basada en printf que evita% de problemas y es única en el sentido de que no devuelve nada (sin carácter de retorno) si hay menos de 4 columnas para imprimir:
cut -f3-
?cut
tampoco tiene expresiones regulares antes de las{}
acciones, y luego es mucho más tonto con los delimitadores de campo (¿número variable de espacios?), Y debe especificarlos manualmente. Creo que el OP quería escuchar sobre algúnshift N
comando, que no existe. El más cercano es$1="";$2="";(...);print}
, pero en mi caso deja algunos espacios iniciales (probablemente separadores).Respuestas:
Una solución que no agrega espacios en blanco adicionales al principio o al final :
Sudo_O propone una elegante mejora utilizando el operador ternario
NF?ORS:OFS
EdMorton ofrece una solución que conserva los espacios en blanco originales entre campos:
BinaryZebra también ofrece dos soluciones increíbles:
(estas soluciones incluso conservan los espacios finales de la cadena original)
La solución dada por larsr en los comentarios es casi correcta:
Esta es la versión fija y parametrizada de la solución larsr :
Todas las demás respuestas antes de septiembre de 2013 son agradables, pero agregan espacios adicionales:
Ejemplo de respuesta agregando espacios iniciales adicionales :
Ejemplo de respuesta agregando espacio adicional al final
fuente
echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
fuente
OFS
ya que no se ocupa, porNF
ejemplo, del espacio al comienzo en los registros.usar corte
o si insiste en awk y $ 13 es el último campo
más
fuente
printf "%s ",$i
, ya que no sabes si$i
podría contener%s
o algo similar. Pero eso imprimiría un espacio extra al final.Prueba esto:
fuente
NF
lo que deja el liderazgoOFS
.La forma correcta de hacer esto es con un intervalo RE porque le permite simplemente indicar cuántos campos omitir y conserva el espacio entre campos para los campos restantes.
por ejemplo, para omitir los primeros 3 campos sin afectar el espacio entre los campos restantes, dado el formato de entrada que parece que estamos discutiendo en esta pregunta, es simplemente:
Si desea acomodar espacios iniciales y espacios no en blanco, pero nuevamente con el FS predeterminado, entonces es:
Si tiene un FS que es un RE que no puede negar en un conjunto de caracteres, puede convertirlo a un solo carácter primero (RS es ideal si es un solo carácter, ya que un RS NO PUEDE aparecer dentro de un campo, de lo contrario, considere SUBSEP), luego aplique la sustitución del intervalo RE, luego conviértalo al OFS. por ejemplo, si las cadenas de "." separan los campos:
Obviamente, si OFS es un solo carácter Y no puede aparecer en los campos de entrada, puede reducirlo a:
Entonces tiene el mismo problema que con todas las soluciones basadas en bucles que reasignan los campos: los FS se convierten en OFS. Si eso es un problema, necesita buscar en la función patsplit () de GNU awks.
fuente
echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
echo ' That is a test' | awk '{print substr($0, index($0,$3))}'
y encontrará que ela
valor de $ 3 coincide con ela
interiorThat
de $ 1. En una versión muy antigua de gawk como la que tiene, debe habilitar los intervalos RE con la bandera--re-interval
.1
es una condición verdadera y por lo tanto invoca la acción awk predeterminada de imprimir el registro actual.Prácticamente todas las respuestas actualmente agregan espacios iniciales, espacios finales o algún otro problema de separador. Para seleccionar desde el cuarto campo donde el separador es un espacio en blanco y el separador de salida es un espacio único, el uso
awk
sería:Para parametrizar el campo de inicio puede hacer:
Y también el campo final:
fuente
Entrada
Salida
fuente
fuente
echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) $(i-2)=$i; NF=NF-2; print $0 }'
ORS
) entre los campos. Bravo por tu iniciativa (me gusta tu respuesta). SaludosOtra forma de evitar el uso de la declaración de impresión:
En awk, cuando una condición es verdadera, la impresión es la acción predeterminada.
fuente
awk '{$1=$2=$3=""}sub("^"OFS"+","")' file
como es el OFS lo que queda después de cambiar los contenidos de $ 1, $ 2 y $ 3.No puedo creer que nadie ofreciera una cáscara simple:
fuente
file
es grande (> 10-30 KB). Para archivos grandes, laawk
solución funciona mejor.Las opciones 1 a 3 tienen problemas con varios espacios en blanco (pero son simples). Esa es la razón para desarrollar las opciones 4 y 5, que procesan múltiples espacios en blanco sin problemas. Por supuesto, si se utilizan las opciones 4 o 5 con
n=0
ambas, se conservarán los espacios en blanco iniciales, lo quen=0
significa que no habrá división.Opción 1
Una solución de corte simple (funciona con delimitadores simples):
opcion 2
Forzar una recalculación de awk a veces resuelve el problema (funciona con algunas versiones de awk) de espacios iniciales agregados:
Opción 3
Imprimir cada campo formateado con
printf
le dará más control:Sin embargo, todas las respuestas anteriores cambian todos los FS entre campos a OFS. Construyamos un par de soluciones para eso.
Opción 4
Un bucle con sub para eliminar campos y delimitadores es más portátil y no activa un cambio de FS a OFS:
NOTA: El "^ [" FS "] *" es para aceptar una entrada con espacios iniciales.
Opcion 5
Es muy posible construir una solución que no agregue espacios en blanco adicionales al principio o al final, y preservar los espacios en blanco existentes usando la función
gensub
de GNU awk, como esta:También se puede usar para intercambiar una lista de campos dado un recuento
n
:Por supuesto, en tal caso, el OFS se utiliza para separar ambas partes de la línea y el espacio en blanco final de los campos aún se imprime.
Nota 1:
["FS"]*
se utiliza para permitir espacios iniciales en la línea de entrada.fuente
" 1 2 3 4 5 6 7 8 "
. Ej .). La opción 4 es buena, pero deja un espacio inicial usando una cadena que comience con un espacio. ¿Crees que esto se puede arreglar? Puede usar el comandoecho " 1 2 3 4 5 6 7 8 " | your awk script | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
para verificar los espaciosCut tiene una marca --complement que hace que sea fácil (y rápido) eliminar columnas. La sintaxis resultante es análoga a lo que desea hacer, lo que hace que la solución sea más fácil de leer / comprender. El complemento también funciona para el caso en el que desee eliminar columnas no contiguas.
fuente
Solución Perl que no agrega espacios en blanco iniciales o finales:
La
@F
matriz perl autosplit comienza en el índice,0
mientras que los campos awk comienzan con$1
Solución Perl para datos delimitados por comas:
Solución de Python:
python -c "import sys;[sys.stdout.write(' '.join(line.split()[3:]) + '\n') for line in sys.stdin]" < file
fuente
Para mí, la solución más compacta y compatible con la solicitud es
Y si tiene más líneas para procesar como, por ejemplo, el archivo foo.txt , no olvide restablecer i a 0:
Gracias tu foro.
fuente
Como me molestó la primera respuesta altamente votada pero incorrecta, encontré suficiente para escribir una respuesta allí, y aquí las respuestas incorrectas están marcadas como tales, aquí está mi parte. No me gustan las soluciones propuestas, ya que no veo ninguna razón para hacer que la respuesta sea tan compleja.
Tengo un registro donde después de $ 5 con una dirección IP puede haber más texto o ningún texto. Necesito todo, desde la dirección IP hasta el final de la línea, en caso de que haya algo después de $ 5. En mi caso, esto es realmente dentro de un programa awk, no un delineador awk, por lo que awk debe resolver el problema. Cuando trato de eliminar los primeros 4 campos usando la respuesta antigua, bonita y con más votos positivos, pero completamente incorrecta:
escupe una respuesta incorrecta e inútil (agregué [] para demostrar):
En cambio, si las columnas tienen un ancho fijo hasta que se necesitan el punto de corte y awk, la respuesta correcta y bastante simple es:
que produce la salida deseada:
fuente
Encontré esta otra posibilidad, quizás también podría ser útil ...
awk 'BEGIN {OFS=ORS="\t" }; {for(i=1; i<14; i++) print $i " "; print $NF "\n" }' your_file
Nota: 1. Para datos tabulares y de la columna $ 1 a $ 14
fuente
Usar corte:
por ejemplo: si tiene
file1
conteniendo:car.is.nice.equal.bmw
Ejecutar:
cut -d . -f1,3 file1
imprimirácar.is.nice
fuente
Esto no está muy lejos de algunas de las respuestas anteriores, pero resuelve un par de problemas:
cols.sh
:Que ahora puedes llamar con un argumento que será la columna de inicio:
O:
Esto está indexado a 1; si prefiere cero indexado, utilice
i=s + 1
en su lugar.Además, si desea tener argumentos para el índice inicial y el índice final, cambie el archivo a:
Por ejemplo:
Las
%-5s
alinea el resultado como columnas de 5 caracteres de ancho; si esto no es suficiente, aumente el número o use%s
(con un espacio) en su lugar si no le importa la alineación.fuente
Solución AWK basada en printf que evita% de problemas y es única en el sentido de que no devuelve nada (sin carácter de retorno) si hay menos de 4 columnas para imprimir:
Pruebas:
fuente