I'd like to substitute some text with an incremental value. Considering file xx:
<outro>dfdfd</outro>
<RecordID>1</RecordID>
<outro>dfdfd</outro>
<RecordID>1</RecordID>
<outro>dfdfd</outro>
<RecordID>1</RecordID>开发者_C百科
<outro>dfdfd</outro>
and sed command:
for n in seq 3;do sed -e 's/<RecordID>\d/<RecordID>'`echo $n`'/' xx; done
the echo $n
command does not get incremented.
Tryed also:
n=1; sed -e 's/<RecordID>/<RecordID>'`echo $n ;let n=$n+1`'/g' xx
but with no success.
Considering only sed (no awk or perl) how can I have the RecordID field incremented as in:
<outro>dfdfd</outro>
<RecordID>1</RecordID>
<outro>dfdfd</outro>
<RecordID>2</RecordID>
<outro>dfdfd</outro>
<RecordID>3</RecordID>
<outro>dfdfd</outro>
while read line; do n=$((++n)) && echo $line|sed -e 's/[0-9]/'$(($n))'/' ; done < patt
Notwithstanding the statement in the question that Perl and Awk cannot be used, the answers given so far demonstrate that sed
is not the correct tool for this task. Both the answers I see only work with an extremely limited set of data and only work sanely on extremely small sets of data.
Using sed
, there isn't a sensible method available to deal with thousands of records. You can hack solutions together, if you're careful, that deal with three record IDs (hint: you might need to map 3 to 4 before you map 2 to 3, lest the mapped 3 be remapped to 4).
Using Perl or Python, it is doable.
perl -e 's{<RecordID>(\d+)</RecordID>}{$n=$n+1; "<RecordID>$n</RecordID>"}e'
This is very much a case of 'use the right tool for the job'. sed
is a great tool for the jobs for which it is designed (and a good many for which it was not designed). However, this is over-stressing it.
First, sed
doesn't understand \d
. Use [0-9]
or [[:digit:]]
instead.
Second, for n in seq 3
will set n
to "seq" and "3". Use for n in $(seq 3)
or (in Bash) use for n in {1..3}
.
Third, you need to save the result of your replacement. If your version of sed
supports -i
(in-place), you can use that or you might need to use sed ... xx > xx.tmp && mv xx.tmp xx
.
Fourth, you need to select which line to make the change to.
Put all that together and this works, but could be quite slow:
for n in $(seq 3); do sed -e $(($n*2))'s/<RecordID>[[:digit:]]/<RecordID>'$n'/' xx > xx.tmp && mv xx.tmp xx; done
The true way to do this with sed is of course to obviate the need for looping in the shell. Use something like Denis' address matcher to narrow down the scope, then use the expressions from the script in sed's info pages. It lexically increments numbers, no arithmetic involved. The sole trick it does is to care for the carry.
精彩评论