Using perl
's /e
regex modifier to evaluate the replacement portion of the s/search/replace/
operator as perl code:
$ perl -p -e 's/B2vpnId=""/sprintf "B2vpnId=\"vpn%i\"", ++$i/e' test
<Set Id="16">
<Ver="44" Sniff="no" B2vpnId="vpn1" Collision="no">
</Set>
<Set Id="17">
<Ver="22" Sniff="no" B2vpnId="vpn2" Collision="no">
</Set>
If you want it to change the files on disk (rather than just output to stdout), use perl's -i
option.
If you are processing multiple files and want it to reset the counter ($i
) after each file, add ; $i=0 if eof
to the end of the script:
$ cp test test2
$ perl -p -e 's/B2vpnId=""/sprintf "B2vpnId=\"vpn%i\"", ++$i/e; $i=0 if eof' test test2
<Set Id="16">
<Ver="44" Sniff="no" B2vpnId="vpn1" Collision="no">
</Set>
<Set Id="17">
<Ver="22" Sniff="no" B2vpnId="vpn2" Collision="no">
</Set>
<Set Id="16">
<Ver="44" Sniff="no" B2vpnId="vpn1" Collision="no">
</Set>
<Set Id="17">
<Ver="22" Sniff="no" B2vpnId="vpn2" Collision="no">
</Set>
Without the $i=0 if eof
statement, the second copy of test would have B2vpnIDs of "vpn3" and "vpn4".
BTW, if you want the counter to start from a different number, e.g. 10, then add BEGIN { $i=9 };
to the beginning of the script. BEGIN
blocks are executed only once before any of the input is read. The rest of the script is executed repeatedly, once for each input line. BTW, there are other kinds of code blocks that are only executed once - from man perlsyn
:
When a block is preceded by a compilation phase keyword such as BEGIN
,
END
, INIT
, CHECK
, or UNITCHECK
, then the block will run only
during the corresponding phase of execution. See perlmod
for more details.
Remember that $i
will be incremented before it is used each time (because the script is using ++$i
rather than $i++
, which would increment it after each use), so subtract 1 from the starting number.
Also remember to change the $i=0 if eof
to match the BEGIN block, e.g., $i=9 if eof
if you're using that.
$ perl -p -e 'BEGIN { $i=9 };
s/B2vpnId=""/sprintf "B2vpnId=\"vpn%i\"", ++$i/e;
$i=9 if eof' test
Or, since we're now using a BEGIN block to initialise $i, we can post-increment it (and use another variable for the starting value so we only have to change it in one place).
$ perl -p -e 'BEGIN { $start = 10; $i = $start };
s/B2vpnId=""/sprintf "B2vpnId=\"vpn%i\"", $i++/e;
$i = $start if eof' test
or even set it to a default value of 1, then if the first arg isn't an existing file set it to the first arg :
$ perl -p -e 'BEGIN {
$start = 1;
$start = shift unless -f $ARGV[0];
$i = $start
};
s/B2vpnId=""/sprintf "B2vpnId=\"vpn%i\"", $i++/e;
$i = $start if eof' 10 test*
awk
, is there a reason why you would not use it? – schrodingerscatcuriosity Nov 30 '21 at 10:14Ver
tags, and missing closing tags). This operation is trivial with an XML parser, but not if the document is faulty. – Kusalananda Nov 30 '21 at 10:33