Reputation: 55
I want to replace all occurrences of a number with a random number in each line of a file using "sed". For example, if my file has the number 892 in each line, I would like to replace that with a unique random number between 800 and 900.
Input file:-
temp11;djaxfile11;892
temp12;djaxfile11;892
temp13;djaxfile11;892
temp14;djaxfile11;892
temp15;djaxfile11;892
Expected output file :-
temp11;djaxfile11;805
temp12;djaxfile11;846
temp13;djaxfile11;833
temp14;djaxfile11;881
temp15;djaxfile11;810
I am trying the below:-
sed -i -- "s/;892/;`echo $RANDOM % 100 + 800 | bc`/g" file.txt
but it is replacing all the occurrences of 892 with a single random number between 800 and 900.
Output file :-
temp11;djaxfile11;821
temp12;djaxfile11;821
temp13;djaxfile11;821
temp14;djaxfile11;821
temp15;djaxfile11;821
Could you please help in correcting my code ? Thanks in advance.
Upvotes: 4
Views: 5062
Reputation: 58440
This might work for you (GNU sed and grep):
sed 's/[^0-9]//g;s/8../\n&\n/g' /dev/random |
grep '^8..' |
sed 'R /dev/stdin' file |
sed 'N;s/892\n//;P;d'
Use /dev/random
to produce a stream of random numbers and break out those which have a string of three numbers beginning with 8
.
Grep the lines for the numbers beginning 800
to 899
.
Append a line from the above file to each line of file
.
If the last 3 characters of the first line begin 892
, remove that number and the following newline (this replaces 892
with a random 800
to 899
number).
Print only the first line of the pair (thus reducing the file to its original size).
Upvotes: 0
Reputation: 44043
With GNU sed, you could do something like
sed '/;892$/ { h; s/.*/echo $((RANDOM % 100 + 800))/e; x; G; s/892\n// }' filename
...but it would be much saner to do it with awk:
awk -F \; 'BEGIN { OFS = FS } $NF == 892 { $NF = int(rand() * 100 + 800) } 1' filename
To make sure that the random numbers are unique, amend the awk code as follows:
awk -F \; 'BEGIN { OFS = FS } $NF == 892 { do { $NF = int(rand() * 100 + 800) } while(!seen[$NF]++) } 1'
Doing that with sed would be too crazy for me. Be aware that this will only work only if there are less than 100 lines with a last field of 892 in the file.
The sed code reads
/;892$/ { # if a line ends with ;892
h # copy it to the hold buffer
s/.*/echo $((RANDOM % 100 + 800))/e # replace the pattern space with the
# output of echo $((...))
# Note: this is a GNU extension
x # swap pattern space and hold buffer
G # append the hold buffer to the PS
# the PS now contains line\nrandom number
s/892\n// # remove the old field and the newline
}
The awk code is much more straightforward. With -F \;
, we tell awk to split the lines at semicolons, then
BEGIN { OFS = FS } # output field separator is input FS, so the output
# is also semicolon-separated
$NF == 892 { # if the last field is 892
# replace it with a random number
$NF = int(rand() * 100 + 800)
}
1 # print.
The amended awk code replaces
$NF = int(rand() * 100 + 800)
with
do {
$NF = int(rand() * 100 + 800)
} while(!seen[$NF]++)
...in other words, it keeps a table of random numbers it has already used and keeps drawing numbers until it gets one it hasn't seen before.
Upvotes: 8