我有一个名为db.txt的文本文件。 文件中的一些样本行如下:
哈利波特和魔法石:J.K。罗琳:21.95:100:200
哈利波特与密室:J.K。罗琳:21.95:150:300
指环王,戒指团契:J.R.R。托尔金:32.00:500:500
权力的游戏:George R.R. Martin: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剪切特定字段然后将整行传入while循环?
例如,如果我进入“哈利波特”, 它应该显示:
哈利波特与魔法石,J.K。罗琳,21.95美元,100,200
哈利波特与密室,J.K。罗琳,21.95美元,150美元,300美元
答案 0 :(得分: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
答案 1 :(得分:4)
grep
和cut
的下一步是awk
。除非你必须使用bash
(这是家庭作业吗?)这样做,否则awk
会使事情变得相当容易:
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
答案 2 :(得分: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不匹配的所有行,然后转换分隔符。
答案 3 :(得分:2)
最简单的方法是查看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
IFS更改将分隔符更改为新行而不是空格,并且awk命令中的FS将分隔符更改为:以允许访问字段
答案 4 :(得分:2)
我知道您没有指定它,但awk
可能是用于此任务的最佳工具。它将cut,sed和grep结合到一个方便易用的工具中。嗯,方便的工具...
要了解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's答案是最好的。
答案 5 :(得分: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