我有一个包含多个模式$$DATABASE_*$$
实例的纯文本文件,星号可以是任何字符串。我想用星号部分中的任何内容替换整个实例,但是小写。
这是一个测试文件:
$$DATABASE_GIBSON$$
test me $$DATABASE_GIBSON$$ test me
$$DATABASE_GIBSON$$ test $$DATABASE_GIBSON$$ test
$$DATABASE_GIBSON$$ $$DATABASE_GIBSON$$$$DATABASE_GIBSON$$
这是所需的输出:
gibson
test me gibson test me
gibson test gibson test
gibson gibsongibson
如何使用sed / awk / tr / perl执行此操作?
答案 0 :(得分:3)
这是我最终使用的perl版本。
perl -p -i.bak -e 's/\$\$DATABASE_(.*?)\$\$/lc($1)/eg' inputFile
答案 1 :(得分:1)
这个用复杂的例子。
perl -ple 's/\$\$DATABASE_(.*?)\$\$/lc($1)/eg' filename.txt
对于更简单的例子:
echo '$$DATABASE_GIBSON$$' | sed 's@$$DATABASE_\(.*\)\$\$@\L\1@'
sed中的,\L
表示小写(如果需要,\E
停止)
答案 2 :(得分:1)
不幸的是,用awk没有简单,万无一失的方法,但这是一种方法:
$ cat tst.awk
{
gsub(/[$][$]/,"\n")
head = ""
tail = $0
while ( match(tail, "\nDATABASE_[^\n]+\n") ) {
head = head substr(tail,1,RSTART-1)
trgt = substr(tail,RSTART,RLENGTH)
tail = substr(tail,RSTART+RLENGTH)
gsub(/\n(DATABASE_)?/,"",trgt)
head = head tolower(trgt)
}
$0 = head tail
gsub("\n","$$")
print
}
$ cat file
The quick brown $$DATABASE_FOX$$ jumped over the lazy $$DATABASE_DOG$$s back.
The grey $$DATABASE_SQUIRREL$$ ate $$DATABASE_NUT$$s under a $$DATABASE_TREE$$.
Put a dollar $$DATABASE_DOL$LAR$$ in the $$ string.
$ awk -f tst.awk file
The quick brown fox jumped over the lazy dogs back.
The grey squirrel ate nuts under a tree.
Put a dollar dol$lar in the $$ string.
注意将$$转换为换行符的技巧,这样我们就可以在匹配(RE)中否定该char,如果没有(即如果我们使用“。+”而不是“[^ \ n] +”)那么由于贪婪的RE匹配,如果相同的模式在一个输入行上出现两次,匹配的字符串将从第一个模式的开头延伸到第二个模式的结尾。
答案 3 :(得分:0)
单独使用awk:
> echo '$$DATABASE_AWESOME$$' | awk '{sub(/.*_/,"");sub(/\$\$$/,"");print tolower($0);}'
awesome
请注意我在FreeBSD中,所以这不是GNU awk。
但这可以单独使用bash来完成:
[ghoti@pc ~]$ foo='$$DATABASE_AWESOME$$'
[ghoti@pc ~]$ foo=${foo##*_}
[ghoti@pc ~]$ foo=${foo%\$\$}
[ghoti@pc ~]$ foo=${foo,,}
[ghoti@pc ~]$ echo $foo
awesome
在上述替换中,除了最后一个(${foo,,}
)之外的所有替换都将在标准Bourne shell中起作用。如果您没有bash,则可以使用tr
执行此步骤:
$ echo $foo
AWESOME
$ foo=$(echo "$foo" | tr '[:upper:]' '[:lower:]')
$ echo $foo
awesome
$
<强>更新强>:
根据评论,似乎OP 真正想要的是从中删除包含它的任何文本中的子字符串 - 也就是说,我们的解决方案需要在他在问题中提供的字符串之前或之后,考虑到领先或尾随空格的可能性。
> echo 'foo $$DATABASE_KITTENS$$ bar' | sed -nE '/\$\$[^$]+\$\$/{;s/.*\$\$DATABASE_//;s/\$\$.*//;p;}' | tr '[:upper:]' '[:lower:]'
kittens
如果您的路径上恰好有pcregrep
(来自devel/pcre
FreeBSD端口),您可以使用它来代替前瞻:
> echo 'foo $$DATABASE_KITTENS$$ bar' | pcregrep -o '(?!\$\$DATABASE_)[A-Z]+(?=\$\$)' | tr '[:upper:]' '[:lower:]'
kittens
(对于阅读此内容的Linux用户:这相当于使用grep -P
。)
在纯粹的狂欢中:
$ shopt -s extglob
$ foo='foo $$DATABASE_KITTENS$$ bar'
$ foo=${foo##*(?)\$\$DATABASE_}
$ foo=${foo%%\$\$*(?)}
$ foo=${foo,,}
$ echo $foo
kittens
请注意,这三个更新的解决方案中的任何一个都不会处理输入中的多个标记数据库名称的情况。这也不是问题的要求,但我只是说'....
答案 4 :(得分:0)
你可以通过supercool命令cut以非常简单的方式执行此操作:)
echo '$$DATABASE_AWESOME$$' | cut -d'$' -f3 | cut -d_ -f2 | tr 'A-Z' 'a-z'
答案 5 :(得分:0)
这可能适合你(GNU sed):
sed 's/$\$/\n/g;s/\nDATABASE_\([^\n]*\)\n/\L\1/g;s/\n/$$/g' file
答案 6 :(得分:0)
这是我能提出的最短(GNU)awk
解决方案,可以完成OP所要求的一切:
awk -vRS='[$][$]DATABASE_([^$]+[$])+[$]' '{ORS=tolower(substr(RT,12,length(RT)-13))}1'
即使用星号(*
)表示的字符串包含一个或多个单个美元符号($
)和/或换行符,这个灵魂分子仍应有效。
答案 7 :(得分:0)
awk '{gsub(/\$\$DATABASE_GIBSON\$\$/,"gibson")}1' file
gibson
test me gibson test me
gibson test gibson test
gibson gibsongibson
答案 8 :(得分:-1)
echo $$DATABASE_WOOLY$$ | awk '{print tolower($0)}'
awk会接受任何输入,在这种情况下是第一次agurment,并使用tolower
函数并返回结果。
对于您的bash脚本,您可以执行类似的操作并使用变量DBLOWER
DBLOWER=$(echo $$DATABASE_WOOLY$$ | awk '{print tolower($0)}');