2013-01-09 26 views
5

Tôi có tệp văn bản có tên db.txt. Một số dòng mẫu từ tệp đi như vậy:Cắt bash Unix và grep

Harry Potter và đá phù thủy: J.K. Rowling: 21.95: 100: 200

Harry Potter và Phòng chứa bí mật: J.K. Rowling: 21.95: 150: 300

Chúa tể của những chiếc nhẫn, Học bổng nhẫn: J.R.R. Tolkien: 32,00: 500: 500

A Game of Thrones: George RR Martin: 44.50: 300: 250

Sau đó, trong kịch bản của tôi, tôi có những dòng sau:

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 

Is có một cách để grep một lĩnh vực cụ thể từ cắt và sau đó vượt qua trong dòng đầy đủ vào vòng lặp while?

Ví dụ, nếu tôi bước vào "Harry Potter", nó sẽ hiển thị:

Harry Potter và Hòn đá phù thủy, J.K. Rowling, $ 21,95, 100, 200

Harry Potter và Phòng chứa bí mật, J.K. Rowling, $ 21,95, 150, 300

+0

Một vòng lặp trên các dòng trong trình bao là không bình thường. Tất cả các lệnh (grep, sed, cut, etc ...) đều sử dụng một vòng lặp trên các dòng. – Zulu

Trả lời

5

Bạn có thể làm điều này mà không cut, và không có grep nếu bạn ok với biểu hiện thường xuyên của bash phù hợp (hoặc có thể sử dụng mẫu vỏ phù hợp với thay).

Ý tưởng sẽ là đọc từng dòng tệp, sau đó chia dòng thành một mảng. Khi bạn đã có điều đó, hãy so sánh và xuất kết quả bạn muốn.

Dưới đây là một bản demo của kỹ thuật này:

#! /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 
+0

Một điều nữa tôi muốn thêm, làm thế nào để bạn kiểm tra trường hợp không nhạy cảm và làm thế nào để tôi đi về in ra những con số ở phía sau? Tôi đã thử% d nhưng con số kết thúc bằng 0. –

+0

Bỏ ghi chú dòng 'shopt' trong bài đăng để nhận được kết quả phân biệt chữ hoa chữ thường. Hãy thử '$%. 02f' cho số tiền đô la,'% d' cho các số nguyên hoạt động tốt với dữ liệu bạn đã cung cấp. – Mat

+0

grep "Harry Potter" db.txt nên làm điều đó! –

4

Bước tiếp theo lên từ grepcutawk. Trừ khi bạn phải làm điều này bằng bash (? Là bài tập về nhà này), sau đó awk sẽ làm cho mọi việc dễ dàng hơn đáng kể:

awk -F: '/harry potter/ { sub(/^/,"$",$(NF-2)); print }' IGNORECASE=1 OFS=", " db.txt 

Kiểm tra đầu vào:

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 

Kiểm tra đầu ra:

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 
2

Các phương pháp dễ nhất để thực hiện việc này là xem qua kết quả 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 

Sự thay đổi IFS thay đổi dấu phân cách để một dòng mới chứ không phải là một không gian và FS trong lệnh awk thay đổi delimiter đến: cho phép truy cập đến các lĩnh vực

3
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 

Các thử nghiệm trong nếu lệnh thực hiện một kết hợp glob đơn giản nhưng không phân biệt, do đó nó sẽ khớp nếu người dùng nhập "potter".

Hoặc, sử dụng sed để thay đổi các thiết bị tách:

read -p "Enter title: " TITLE 
sed '/'"$TITLE"'/I!d; s/:/, /g' db.txt 

có nghĩa là xóa tất cả các dòng mà không phù hợp với TITLE, sau đó chuyển các dấu phân cách.

1

Nếu bạn có thể sử dụng sed đây sẽ là một giải pháp

read -p "Enter title: " TITLE 
    sed -n -e 's/^\([^:]\+:\)\{2\}/\0$/' -e 's/:/, /g' -e "/^$TITLE/Ip" db.txt 

lời giải thích ngắn những gì nó làm

-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 
2

Tôi biết bạn không nói rõ điều đó, nhưng awk có lẽ là công cụ tốt nhất để sử dụng cho nhiệm vụ này. Nó kết hợp cắt, sed và grep thành một công cụ thuận tiện và dễ sử dụng. Vâng, công cụ thuận tiện ...

Để hiểu awk, bạn phải hiểu một vài điều:

  • AWK là một ngôn ngữ lập trình. Nó đã được xây dựng trong logic và các biến.
  • Awk giả định một vòng đọc đọc mỗi dòng.
  • Các chương trình Awk phải được bao quanh bởi các dấu ngoặc nhọn.
  • Không chỉ dấu ngoặc nhọn, nhưng biến phân tích cú pháp Awk bắt đầu bằng dấu đô la. Vì vậy, bạn cần phải đặt các chương trình Awk của bạn được bao quanh bởi dấu nháy đơn để giữ cho trình bao ra khỏi nó.
  • Tự động phân tích cú pháp mỗi dòng dựa trên bộ tách trường . Trình tách trường mặc định là khoảng trắng trong khi bạn có thể thay đổi thông số đó thông qua tham số -f.
  • Mỗi trường nhận một biến đặc biệt. Trường đầu tiên là $1, trường tiếp theo là $2, vv Toàn bộ dòng là $0.

Đây là tuyên bố AWK của bạn:

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 

Tất nhiên, toàn bộ điều có thể là một dòng đơn quá:

awk -F: '{ print "I read " $4 " pages " out of " $5 " of " $1 " by " $2 "." }' $file 

Chỉ muốn nhấn mạnh programability của AWK và làm thế nào nó có thể được sử dụng để làm kiểu phân tích cú pháp này.

Nếu câu hỏi của bạn là cách nhập thông tin này và đặt nó vào biến môi trường, câu trả lời là Glenn Jackman's là tốt nhất.

Các vấn đề liên quan