Necesito ayuda para descubrir cómo usar el comando sed para mostrar solo la primera columna y la última columna en un archivo de texto. Esto es lo que tengo hasta ahora para la columna 1:
cat logfile | sed "s/\|/ /"|awk "{print $1}"
Mi débil intento de mostrar la última columna también fue:
cat logfile | sed "s/\|/ /"|awk "{print $1}{print $8}"
Sin embargo, esto toma la primera columna y la última columna y las fusiona en una lista. ¿Hay alguna forma de imprimir la primera y la última columna claramente con los comandos sed y awk?
Ejemplo de entrada:
foo|dog|cat|mouse|lion|ox|tiger|bar
Comentarios
- Proporcione una entrada de muestra.
Respuesta
Casi llego. Simplemente coloque las referencias de ambas columnas una al lado de la otra.
cat logfile | sed "s/|/ /" | awk "{print $1, $8}"
También tenga en cuenta que no necesita cat aquí .
sed "s/|/ /" logfile | awk "{print $1, $8}"
También tenga en cuenta que puede decirle a awk que los separadores de columna son |, en lugar de espacios en blanco, por lo que tampoco necesita sed.
awk -F "|" "{print $1, $8}" logfile
Según las sugerencias de Caleb , si desea una solución que aún muestre el último campo , incluso si no hay exactamente ocho, puede usar $NF.
awk -F "|" "{print $1, $NF}" logfile
Además, si desea salida para retener los separadores |, en lugar de usar un espacio, puede especificar los separadores de campo de salida. Desafortunadamente, es un poco más torpe que simplemente usar el indicador -F, pero aquí hay tres enfoques.
-
Puede asignar la entrada y separadores de campo de salida en
awkmismo, en el bloque BEGIN.awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile -
Puede asignar estas variables al llamar a
awkdesde la línea de comando, a través del indicador-v.awk -v "FS=|" -v "OFS=|" "{print $1, $8}" logfile -
o simplemente:
awk -F "|" "{print $1 "|" $8}" logfile
Comentarios
- Buen trabajo desglosando cómo se puede simplificar este problema. Podría agregar una nota sobre cómo usar
|como separador de salida en lugar de el espacio predeterminado para la concatenación de cadenas. También puede explicar el uso de$NFen lugar de codificar$8para obtener la última columna. - después de eso, ¿cómo actualizar el archivo?
- @pankajprasad Escribir en un nuevo archivo con h
>luego sobrescriba el anterior o usesponge. Sin embargo, esta es realmente una pregunta nueva. - @Sparhawk funciona, pero se borra el contenido de escariado. ¿cómo lidiar con eso?
- @pankajprasad Necesitas hacer una nueva pregunta. Haga clic en el gran botón azul en la parte superior que dice » Preguntar «.
Responder
De todos modos, estás usando awk:
awk "{ print $1, $NF }" file
Comentarios
- No ‘ t necesita especificar el separador de campo de entrada (ya que en este caso parece ser
|en lugar de ese espacio) con-F\|o similar? Además, ¿qué pasaría si quisiera usar el mismo delimitador para la salida? - @Caleb Probablemente: estaba esperando que el OP confirmara cómo exactamente era la entrada, en lugar de intentar adivinar basado en los ejemplos que no funcionan …
- Tenga en cuenta que se supone que la entrada contiene al menos 2 campos.
- @St é phaneChazelas OP indicó claramente en el código que tiene ocho campos, siempre.
- @ michaelb958 Creo » claramente » está exagerando el caso, solo un poco 🙂
Respuesta
Simplemente reemplace del primero al último | con un | (o espacio si lo prefiere):
sed "s/|.*|/|/"
Tenga en cuenta que, aunque no hay una implementación sed donde | sea especial (siempre que extendido las expresiones no están habilitadas a través de -E o en algunas implementaciones), \| en sí es especial en algunas como GNU sed. Por lo tanto, no debe escapar de | si desea que coincida con el carácter |.
Si reemplaza con espacio y si la entrada ya puede contener líneas con solo un |, entonces, «tendrá que tratarlo especialmente como |.*| no coincidirá con esos.Podría ser:
sed "s/|\(.*|\)\{0,1\}/ /"
(es decir, hacer que la parte .*| sea opcional) O:
sed "s/|.*|/ /;s/|/ /"
o:
sed "s/\([^|]*\).*|/\1 /"
Si desea el primer y octavo campo independientemente del número de campos en la entrada, entonces es simplemente:
cut -d"|" -f1,8
(todos estos funcionarían con cualquier utilidad compatible con POSIX asumiendo la entrada forma texto válido (en particular, los sed generalmente no funcionarán si la entrada tiene bytes o secuencias de bytes que no forman caracteres válidos en la configuración regional actual como por ejemplo printf "unix|St\351phane|Chazelas\n" | sed "s/|.*|/|/" en una configuración regional UTF-8)).
Respuesta
Si te encuentras sin awk y sin sed, puedes lograr el lo mismo con coreutils:
paste <( cut -d"|" -f1 file) \ <(rev file | cut -d"|" -f1 | rev)
Comentarios
-
cutes más limpio y compacto que awk / sed cuando solo está interesado en la primera columna, o si los delimitadores son fijos (es decir, no un número variable de espacios). - ¡Bastante elegante!
Responder
Parece que estás intentando obtener el primer y último campo de texto que está delimitado por |.
Asumí que su archivo de registro contiene el texto que se muestra a continuación,
foo|dog|cat|mouse|lion|ox|tiger|bar bar|dog|cat|mouse|lion|ox|tiger|foo
Y desea la salida como,
foo bar bar foo
Si es así, aquí viene el comando para su «s
A través de GNU sed,
sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" file
Ejemplo:
$ echo "foo|dog|cat|mouse|lion|ox|tiger|bar" | sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" foo bar
Comentarios
- Las columnas no están delimitadas por una tubería | pero están en columnas, estoy interesado en usar sed pero no usar el comando awk como lo hizo en su comando: sed -r ‘ s ~ ^ ([^ |] *) . * \ | (. *) $ ~ \ 1 \ 2 ~ ‘ archivo
- » Las columnas son no delimitado por una tubería | pero están en columnas «, ¿quiere decir que las columnas están separadas por espacios?
- Una entrada de muestra y una salida sería mejor.
Respuesta
Probablemente deberías hacerlo con sed – lo haría de todos modos – pero, solo porque nadie ha escrito este todavía:
while IFS=\| read col1 cols do printf %10s%-s\\n "$col1 |" " ${cols##*|}" done <<\INPUT foo|dog|cat|mouse|lion|ox|tiger|bar INPUT
SALIDA
foo | bar