comando - Unix bash cutting y grep
cut lines linux command (6)
El método más fácil de hacer esto es mirar los resultados de grep
#!/bin/bash
read -p "Enter title: " TITLE
FILENAME="db.txt"
IFS=$''/n''
for LINE in `grep -iw "Harry Potter" "$FILENAME"`; do
echo $LINE | awk ''BEGIN { FS = ":" } ; { print $1, $2, $3, $4, $5 }''
done
El cambio IFS cambia el delimitador a una nueva línea en lugar de un espacio y el FS en el comando awk cambia el delimitador a: para permitir el acceso a los campos
Tengo un archivo de texto llamado db.txt. Algunas líneas de muestra del archivo son las siguientes:
Harry Potter y la piedra de hechicero: JK Rowling: 21.95: 100: 200
Harry Potter y la Cámara de los Secretos: JK Rowling: 21.95: 150: 300
El señor de los anillos, La comunidad del anillo: JRR Tolkien: 32.00: 500: 500
Un juego de tronos: George RR Martin: 44.50: 300: 250
Luego en mi script, tengo las siguientes líneas:
echo "Enter title:"
read TITLE
cut -d ":" -f 1 db.txt | grep -iw "$TITLE" | while read LINE
do
STRING="`echo $LINE | cut -d ":" -f 1`,"
STRING="$STRING `echo $LINE | cut -d ":" -f 2`, "
STRING=" /$$STRING`echo $LINE | cut -d ":" -f 3`,"
STRING=" $STRING`echo $LINE | cut -d ":" -f 4`,"
STRING=" $STRING`echo $LINE | cut -d ":" -f 5`"
done
¿Hay alguna manera de grep un campo específico de corte y luego pasar en la línea completa en el ciclo while?
Por ejemplo, si ingresé "Harry Potter", debería mostrar:
Harry Potter y la piedra de brujo, JK Rowling, $ 21.95, 100, 200
Harry Potter y la Cámara de los Secretos, JK Rowling, $ 21.95, 150, 300
El siguiente paso desde grep
y cut
es awk
. A menos que tengas que hacer esto usando bash
(¿es esta tarea?), Entonces awk
facilitaría mucho las cosas:
awk -F: ''/harry potter/ { sub(/^/,"$",$(NF-2)); print }'' IGNORECASE=1 OFS=", " db.txt
Entrada de prueba:
Harry Potter and the Sorcerer''s Stone:J.K. Rowling:21.95:100:200
Harry Potter and the Chamber of Secrets:J.K. Rowling:21.95:150:300
Lord of the Rings, The Fellowship of the Ring:J.R.R. Tolkien:32.00:500:500
A Game of Thrones:George R.R. Martin:44.50:300:250
Prueba de salida:
Harry Potter and the Sorcerer''s Stone, J.K. Rowling, $21.95, 100, 200
Harry Potter and the Chamber of Secrets, J.K. Rowling, $21.95, 150, 300
Puede hacer esto sin cut
, y sin grep
si está bien con la coincidencia de expresión regular de bash (o puede usar la coincidencia de patrón de shell en su lugar).
La idea sería leer el archivo línea por línea, luego dividir la línea en una matriz. Una vez que tenga eso, haga las comparaciones y la producción que desee.
Aquí hay una demostración de la técnica:
#! /bin/bash
echo "Title:"
read title
# shopt -s nocasematch # if you want case-insensitive matching
while read line ; do # this read takes data from input.txt, see
# end of loop
IFS=: read -a parts <<< "$line" # this splits the line on ":" into
# an array called parts
if [[ ${parts[0]} =~ $title ]] ; then # regex matching
printf "%s -- %s/n" "${parts[1]}" "${parts[2]}"
fi
done < input.txt
Si puedes usar sed
esto sería una solución
read -p "Enter title: " TITLE
sed -n -e ''s/^/([^:]/+:/)/{2/}//0$/'' -e ''s/:/, /g'' -e "/^$TITLE/Ip" db.txt
Breve explicación de lo que hace
-n tells sed not to print any lines
-e ''s/^/([^:]/+:/)/{2/}//0$/'' matches for the 2nd : and adds a $ after it
-e ''s/:/, /g'' replaces all : with , and a following whitespace
-e "/^$TITLE/Ip" tells sed to print all lines which start with $TITLE (that''s the p) and I tells sed to match case-insensitive
read -p "Enter title: " TITLE
while IFS=: read title author price x y; do
if [[ ${title,,} == *${TITLE,,}* ]]; then
printf "%s, %s, $%s, %s, %s/n" "$title" "$author" "$price" "$x" "$y"
fi
done < db.txt
La prueba en el comando if hace un simple emparejamiento global, pero insensiblemente, por lo que coincidirá si el usuario ingresa "potter".
O bien, use sed para cambiar los separadores:
read -p "Enter title: " TITLE
sed ''/''"$TITLE"''/I!d; s/:/, /g'' db.txt
lo que significa que elimina todas las líneas que no coinciden con el TÍTULO, luego transforma el separador.
Sé que no lo especificó, pero awk
es probablemente la mejor herramienta para usar en esta tarea. Combina cut, sed y grep en una herramienta práctica y fácil de usar. Bueno, una herramienta conveniente ...
Para entender awk
, debes entender algunas cosas:
- Awk es un lenguaje de programación. Ha construido en lógica y variables.
- Awk supone un ciclo de lectura que lee todas y cada una de las líneas.
- Los programas Awk deben estar rodeados de llaves.
- No solo las llaves, sino que las variables de análisis de Awk comienzan con signos de dólar. Por lo tanto, debe poner sus programas Awk rodeados por comillas simples para mantener el shell fuera de él.
- Awk analiza automáticamente cada línea en función del separador de campo . El separador de campo predeterminado es un espacio de tiempo, pero puede cambiarlo a través del parámetro
-f
. - Cada campo obtiene una variable especial. El primer campo es
$1
, el siguiente campo es$2
, etc. Toda la línea es$0
.
Aquí está tu declaración de Awk:
awk -F: ''{
title = $1
author = $2
price = $3
pages_read_until_i_got_bored=$4
pages = $5
print "I read " pages_read_until_i_gob_bored "pages out of " $pages " pages of " $title " by " $author "."
}'' $file
Por supuesto, todo el asunto podría ser una sola línea también:
awk -F: ''{ print "I read " $4 " pages " out of " $5 " of " $1 " by " $2 "." }'' $file
Solo quería enfatizar la programabilidad de Awk y cómo se puede usar para hacer este tipo de análisis.
Si su pregunta es cómo ingresar esta información y ponerla en variables de entorno, la respuesta de Glenn Jackman es la mejor.