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
awk
mismo, en el bloque BEGIN.awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile
-
Puede asignar estas variables al llamar a
awk
desde 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$NF
en lugar de codificar$8
para 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
-
cut
es 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