5

我有一个名为 db.txt 的文本文件。文件中的一些示例行如下所示:

哈利波特与魔法石:JK罗琳:21.95:100:200

哈利波特与密室:JK罗琳:21.95:150:300

指环王,魔戒:JRR 托尔金:32.00:500:500

权力的游戏:乔治·RR·马丁:44.50:300:250

然后在我的脚本中,我有以下几行:

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

有没有办法从 cut 中 grep 特定字段,然后将整行传递到 while 循环中?

例如,如果我输入“哈利波特”,它应该显示:

哈利波特与魔法石,JK 罗琳,21.95 美元、100 美元、200 美元

哈利波特与密室,JK 罗琳,21.95 美元、150 美元、300 美元

4

6 回答 6

5

如果你对 bash 的正则表达式匹配没问题(或者可以使用 shell 模式匹配) ,你可以在没有cut, 和没有的情况下执行此操作。grep

这个想法是逐行读取文件,然后将该行拆分为一个数组。一旦你得到了,做你想要的比较和输出。

这是该技术的演示:

#! /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
于 2013-01-09T14:22:36.517 回答
4

下一步是grep和。除非您必须使用(这是作业吗?)来执行此操作,否则会使事情变得容易得多:cutawkbashawk

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

测试输入:

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

测试输出:

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
于 2013-01-09T14:26:56.133 回答
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

if 命令中的测试执行简单的全局匹配但不区分大小写,因此如果用户输入“potter”,它将匹配。

或者,使用 sed 更改分隔符:

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

这意味着删除所有与 TITLE 不匹配的行,然后转换分隔符。

于 2013-01-09T14:31:04.637 回答
2

The easiest method of doing this is to look over the grep results

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

The IFS change changes the delimiter to a new line rather than a space and the FS in the awk command changes the delimiter to the : to allow access to the fields

于 2013-01-09T14:29:09.790 回答
2

我知道您没有指定它,但awk它可能是用于此任务的最佳工具。它将 cut、sed 和 grep 组合成一个方便易用的工具。嗯,方便的工具...

要了解awk,您必须了解以下几点:

  • awk 是一种编程语言。它内置了逻辑和变量。
  • awk 假设一个读取循环读取每一行。
  • awk 程序必须用花括号括起来。
  • 不仅是花括号,而且 Awk 解析变量都以美元符号开头。因此,您需要将您的 awk 程序用单引号括起来以防止 shell 进入。
  • awk 根据字段分隔符自动解析每一行。默认字段分隔符是一个空格,但您可以通过-f参数更改它。
  • 每个字段都有一个特殊的变量。第一个字段是$1,下一个字段是$2,依此类推。整行是$0

这是您的 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

当然,整个事情也可以是一行:

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

只是想强调 Awk 的可编程性以及如何使用它来进行这种类型的解析。

如果您的问题是如何输入这些信息并将其放入环境变量中,那么Glenn Jackman 的回答是最好的。

于 2013-01-09T14:59:01.867 回答
1

如果你可以使用sed这将是一个解决方案

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

简短说明它的作用

 -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
于 2013-01-09T14:31:38.507 回答