Bash 以错误的方式使用awk
我被告知我在下面的代码中以错误的方式使用了awk,但对于如何改进我的代码以使其更易于阅读,我感到目瞪口呆Bash 以错误的方式使用awk,bash,shell,awk,Bash,Shell,Awk,我被告知我在下面的代码中以错误的方式使用了awk,但对于如何改进我的代码以使其更易于阅读,我感到目瞪口呆 read -r bookName read -r authorName if grep -iqx "$bookName:$authorName" cutText.txt then lineNum=`awk -v bookName="$bookName" -v authorName="$authorName" '$0 ~ bookName ":" authorName {print
read -r bookName
read -r authorName
if grep -iqx "$bookName:$authorName" cutText.txt
then
lineNum=`awk -v bookName="$bookName" -v authorName="$authorName" '$0 ~ bookName ":" authorName {print NR} BEGIN{IGNORECASE=1}' BookDB.txt`
echo "Enter a new title"
read -r newTitle
awk -F":" -v bookName="$bookName" -v newTitle="$newTitle" -v lineNum="$lineNum" 'NR==lineNum{gsub(bookName, newTitle)}1' cutText.txt > temp2.txt
mv -f temp2.txt cutText.txt
else
echo "Error"
fi
My cutText.txt包含如下内容:
Hairy Potter:Rihanna
MARY IS A LITTLE LAMB:Kenny
Sing along:May
该程序基本上更新了cutText.txt中的新标题。如果用户想将MARY IS a LITTLE LAMB
更改为MARY not a LAMB
,他将输入新标题,cutText.txt
将用MARY not a LAMB
替换原始标题
现在出现了一个问题,如果用户在$newTitle
中输入“Mary是一只小羊羔”,那么这个工作代码就不起作用了,因为它考虑到了这个情况。
只有当用户输入“MARY是一只小羊羔”时,它才会起作用。我开始意识到BEGIN{IGNORECASE=1}
是gawk sepcific,因此不能在awk中使用
如何更好地编写脚本,以便在用户输入中忽略大小写?谢谢大家! 好了,伙计们,我刚意识到我是个笨蛋**** 我一整天都在扯头发,我所要做的就是这么做
lineNum=`grep -in "$bookName:$authorName" BookDB.txt | cut -f1 -d":"`
sed -i "${lineNum}s/$bookName/$newTitle/I" BookDB.txt cutText.txt
天哪,我真想自杀。好了,伙计们,我刚意识到我也是个哑巴**** 我一整天都在扯头发,我所要做的就是这么做
lineNum=`grep -in "$bookName:$authorName" BookDB.txt | cut -f1 -d":"`
sed -i "${lineNum}s/$bookName/$newTitle/I" BookDB.txt cutText.txt
天哪,我真想自杀。让你开始吧。创建文件 r.awk
function asplit(str, arr, sep, temp, i, n) { # make an assoc array from str
n = split(str, temp, sep)
for (i = 1; i <= n; i++)
arr[temp[i]]++
return n
}
function regexpify(s, back, quote, rest, all, meta, n, c, u, l, ans) {
back = "\\"; quote = "\"";
rest = "^$.[]|()*+?"
all = back quote rest
asplit(all, meta, "")
n = length(s)
for (i=1; i<=n; i++) {
c = substr(s, i, 1)
if (c in meta)
ans = ans back c
else if ((u = toupper(c)) != (l = tolower(c)))
ans = ans "[" l u "]"
else
ans = ans c
}
return ans
}
BEGIN {
old = regexpify(old)
sep = ":"; m = length(sep)
}
NR == n {
i = index($0, sep)
fst = substr($0, 1, i-m)
scn = substr($0, i+m )
gsub(old, new, fst)
print fst sep scn
next
}
{
print
}
用法:
awk -v n=2 -v old="MArY iS A LIttLE lAmb" -v new="Mary is not a lamb" -f r.awk cutText.txt
预期产出:
Hairy Potter:Rihanna
Mary is not a lamb:Kenny
Sing along:May
让你开始。创建文件 r.awk
function asplit(str, arr, sep, temp, i, n) { # make an assoc array from str
n = split(str, temp, sep)
for (i = 1; i <= n; i++)
arr[temp[i]]++
return n
}
function regexpify(s, back, quote, rest, all, meta, n, c, u, l, ans) {
back = "\\"; quote = "\"";
rest = "^$.[]|()*+?"
all = back quote rest
asplit(all, meta, "")
n = length(s)
for (i=1; i<=n; i++) {
c = substr(s, i, 1)
if (c in meta)
ans = ans back c
else if ((u = toupper(c)) != (l = tolower(c)))
ans = ans "[" l u "]"
else
ans = ans c
}
return ans
}
BEGIN {
old = regexpify(old)
sep = ":"; m = length(sep)
}
NR == n {
i = index($0, sep)
fst = substr($0, 1, i-m)
scn = substr($0, i+m )
gsub(old, new, fst)
print fst sep scn
next
}
{
print
}
用法:
awk -v n=2 -v old="MArY iS A LIttLE lAmb" -v new="Mary is not a lamb" -f r.awk cutText.txt
预期产出:
Hairy Potter:Rihanna
Mary is not a lamb:Kenny
Sing along:May
这将使用精确的字符串匹配,因此在部分匹配时,或者如果旧标题包含
:
或regexp元字符,或者如果新标题包含反引用(例如&
),或者如果反斜杠(\
)出现在迄今为止其他脚本将失败的任何字段或任何其他情况中:
$ cat tst.sh
read -r oldTitle
read -r authorName
echo "Enter a new title"
read -r newTitle
awk '
BEGIN {
ot=ARGV[1]; nt=ARGV[2]; an=ARGV[3]
ARGV[1] = ARGV[2] = ARGV[3] = ""
}
tolower($0) == tolower(ot":"an) {
$0 = nt":"an
found = 1
}
{ print }
END {
if ( !found ) {
print "Error" | "cat>&2"
}
}
' "$oldTitle" "$newTitle" "$authorName" cutText.txt > temp2.txt &&
mv -f temp2.txt cutText.txt
我正在从ARGV[]填充awk变量,因为如果我在arg列表中使用-v var=val
或var=val
填充它们,那么任何反斜杠都将被解释,因此,例如\t
,将成为文本制表符。请参阅我很久以前写的shell常见问题解答文章-
顺便说一句,我把书名
改为旧标题
,因为这似乎对新标题
更有意义。没有功能上的差异
在进行任何文本操作时,了解字符串和各种regexp风格(BREs/EREs/PCREs)之间的差异以及部分匹配和完全匹配之间的差异是非常重要的
-E
arg,在PCRE上运行的是-P
arg,在字符串上运行的是-F
arg-E
参数的ERE上运行。sed不支持PCREs。sed也不能对字符串进行操作,要使regexp表现得像字符串一样令人痛苦,请参阅因此,如果像您的情况一样,您需要对文本中的所有字符进行逐字处理,那么这是一个字符串,而不是regexp,因此您不应该在其上使用sed,如果您希望在文件中快速找到字符串并对部分匹配感到满意,您应该使用grep,但是,如果您想做除此之外的任何事情,如更改文件中的字符串或进行精确匹配,则应使用awk。这使用精确的字符串匹配,因此在部分匹配或旧标题包含
:
或regexp元字符,或者如果新标题包含反向引用,则不能失败(例如,&
)或如果任何字段中出现反斜杠(\
),或您的其他脚本到目前为止将失败的任何其他情况:
$ cat tst.sh
read -r oldTitle
read -r authorName
echo "Enter a new title"
read -r newTitle
awk '
BEGIN {
ot=ARGV[1]; nt=ARGV[2]; an=ARGV[3]
ARGV[1] = ARGV[2] = ARGV[3] = ""
}
tolower($0) == tolower(ot":"an) {
$0 = nt":"an
found = 1
}
{ print }
END {
if ( !found ) {
print "Error" | "cat>&2"
}
}
' "$oldTitle" "$newTitle" "$authorName" cutText.txt > temp2.txt &&
mv -f temp2.txt cutText.txt
我从ARGV[]填充awk变量,因为如果我在arg列表中使用-v var=val
或var=val
填充它们,那么任何反斜杠都会被解释,因此\t
将成为一个文本制表符。请参阅我很久以前写的shell FAQ文章-
顺便说一句,我把bookName
改成了oldTitle
,因为这似乎对newTitle
更有意义。没有功能上的区别
在进行任何文本操作时,了解字符串和各种regexp风格(BREs/EREs/PCREs)之间的差异以及部分匹配和完全匹配之间的差异是非常重要的
-E
arg,在PCRE上运行的是-P
arg,在字符串上运行的是-F
arg-E
参数。sed不支持PCREs。sed也不能在字符串上操作,要使regexp表现得像字符串一样令人痛苦,请参阅awk
唯一的问题。您可能应该删除bash
和shell
标记。并且您可能应该将问题简化为如何告诉非GNU awk忽略模式中的大小写?,并提供一个小示例,说明您有什么行为以及您想要什么行为。说明您的版本属于awk