Reputation: 87
Given the string below, how can I replace 6th and 7th by getting 14th and 15th digit using awk or sed.
xxxxx02xxxxxx89xx
xxxxx22xxxxxx33xx
output
xxxxx89xxxxxx89xx
xxxxx33xxxxxx33xx
I am newbie here, sorry for my question.
Upvotes: 1
Views: 21877
Reputation: 241671
The sed command is straightforward, but hard to read:
sed 's/\(.....\)..\(......\)\(..\)/\1\3\2\3/'
A possibly more maintainable solution can be had with Gnu awk
(but not other awk varieties. However, see below.):
gawk -v FIELDWIDTHS="5 2 6 2 999" -v OFS='' '{$2=$4;print}'
The FIELDWIDTHS
variable defines 5 fixed-width fields: the first 5 characters, the next two characters (positions 6 and 7); the next six characters (8 through 13); the next two characters (14 and 15); and the next (up to) 999 characters, which should be the rest of the line. (If you have longer lines, increase as necessary). Setting OFS
to empty is often useful with fixed-length fields; it prevents awk
from inserting spaces between fields in the output.
FIELDWIDTHS
is a GNU awk extension. However, it is easy enough to reimplement in Posix awk
. Here's a simple implementation:
function fieldwidth_set( i) {
if (PROCINFO["FS"]) FIELDWIDTHS = FIELDWIDTHS;
else if (length(FIELDWIDTHS)) {
_FW_NF = split(FIELDWIDTHS, _FW_ARRAY);
for (i in _FW_ARRAY) {
if (_FW_ARRAY[i] !~ /^[0-9]+$/) {
printf "Illegal value '%s' in FIELDWIDTHS\n", _FW_ARRAY[i] >>"/dev/stderr";
exit 1;
}
_FW_ARRAY[i]+=0;
}
} else
_FW_NF = 0;
}
function set_fieldwidth(fw) { FIELDWIDTHS=fw; fieldwidth_set(); }
function fw_( a,i,k) {
if (_FW_NF) {
a = $0;
$0 = "";
k=1;
for (i=1; i<=_FW_NF; ++i) {
$i = substr(a, k, _FW_ARRAY[i]);
k+=_FW_ARRAY[i];
}
}
}
BEGIN{set_fieldwidth()}
{fw_()}
As far as I know, only Gnu awk lets you mix program files and program text on the awk
command-line. Posix requires the -f program-file
option, which may be repeated, but does not require the -e program-text
option as implemented by Gnu awk. Consequently, if you want to use the above snippet with a command-line awk program, you need to do something like this:
awk -v FIELDWIDTHS="5 2 6 2 999" -v OFS= -f fw.awk -f <(echo '{$2=$4;print}')
(Assuming you put the fieldwidth snippet into fw.awk
.)
For efficiency, fw.awk
insists that you tell it that you've changed FIELDWIDTHS
by calling fieldwidth_set()
. Or you can use set_fieldwidth("....")
to set FIELDWIDTHS
to a new value. It will work with GNU awk as well as with other awk implementations; it lets GNU awk do the heavy lifting.
Upvotes: 3
Reputation: 41446
This should follow your request and work with all awk
:
awk '{$6=$14;$7=$15}1' FS= OFS= file
xxxxx89xxxxxx89xx
xxxxx33xxxxxx33xx
It will change the digit in position 6
by the one in 14
and the one in 7
with the one int 15
If FS=""
does not work, try this:
awk '{n=split($0,a,"");a[6]=a[14];a[7]=a[15];for (i=1;i<=n;i++) printf "%s",a[i];print ""}' input
As request in one of the comment:
It works, thanks! How about if I want to replace 14th and 15th digit by 6th and 7th digit? – Vision111
awk '{$14=$6;$15=$7}1' FS= OFS= file
Upvotes: 2
Reputation:
This will work without GNU awk GAWK
awk 'sub(/[0-9]+/,substr($0,14,2))' file
Or longer but more generic
awk '{print substr($0,0,5) substr($0,14,2) substr($0,8)}' file
RESULT:
xxxxx89xxxxxx89xx
xxxxx33xxxxxx33xx
Upvotes: 1
Reputation: 174696
You could try the below sed command,
$ echo 'xxxxx03xxxxxx75xx' | sed -r 's/^(.{5})(..)(.{6})../\1\2\3\2/g'
xxxxx03xxxxxx03xx
$ echo 'xxxxx03xxxxxx75xx' | sed 's/^\(.\{5\}\)\(..\)\(.\{6\}\)../\1\2\3\2/g'
xxxxx03xxxxxx03xx
It replaces 14th and 15th digits with the digits in the position 6 and 7th.
$ echo 'xxxxx03xxxxxx75xx' | sed -r 's/^(.{5})..(.{6})(..)/\1\3\2\3/g'
xxxxx75xxxxxx75xx
$ echo 'xxxxx03xxxxxx75xx' | sed 's/^\(.\{5\}\)..\(.\{6\}\)\(..\)/\1\3\2\3/g'
xxxxx75xxxxxx75xx
It replaces 6th and 7th digits with the digits in the position 14th and 15th.
Upvotes: 2