13

I'm trying to add random string for each line while running:

awk '{print "name" "'$ran'" "-"$0}' 'myfile'

Before that, the random string is generated:

ran="$(tr -dc '[:alnum:]' </dev/urandom | head -c 6)"

The problem is that it will print the same random string for each line:

nameGQz3Ek-
nameGQz3Ek-
nameGQz3Ek-

What should I do in order to get different random string for each line?

1
  • Instead of some variation of tr -dc '[:alnum:]' </dev/urandom | head -c 6, it would simpler and more computationally efficient to use pwgen -s 6 1, or better yet pwgen -s 6 $(wc -l myfile) will give you exactly all the random strings you need, in one shot. Commented Mar 7, 2018 at 14:48

7 Answers 7

10

Don't you think its bit obvious? You are just generating random string once and storing it in ran variable and using it for all the lines!

Using getline into a variable from a pipe

awk '{
     str_generator = "tr -dc '[:alnum:]' </dev/urandom | head -c 6"
     str_generator | getline random_str
     close(str_generator)
     print "name " random_str " - " $0
}' file

When you use command | getline var, the output of command is sent through a pipe to getline() and into the variable var.

Also note when a pipe is opened for output, awk remembers the command associated with it, and subsequent writes to the command are appended to the previous writes. We need to make an explicit close() call of the command to prevent that.

If the nested single-quotes in the str_generator are causing a problem, replace with its octal equivalent(\047)

awk '{
     str_generator = "tr -dc \047[:alnum:]\047 </dev/urandom | head -c 6"
     str_generator | getline random_str
     close(str_generator)
     print "name " random_str " - " $0
}' file
9

With awk system() function:

Sample input.txt:

a
b
c

awk '{ 
         printf "name";
         system("tr -dc \047[:alnum:]\047 </dev/urandom | head -c6");
         printf "-%s\n", $0
     }' input.txt

Sample output:

nameSDbQ7T-a
nameAliHY0-b
nameDUGP2S-c

system(command)
Execute the operating system command command and then return to the awk program

https://www.gnu.org/software/gawk/manual/gawk.html#index-system_0028_0029-function

2
  • Nice, but why I'm getting tr: write error: Broken pipe?
    – user134969
    Commented Mar 7, 2018 at 13:23
  • @user134969, it works fine. Make sure that you haven't made any errors at the command line Commented Mar 7, 2018 at 13:24
8

Running one instance of tr -dc '[:alnum:]' </dev/urandom | head -c 6 per line of input would be counter-productive, you'd be better of doing:

<input awk -v rng="LC_ALL=C tr -dc '[:alnum:]' </dev/urandom | fold -w 6" '
  {rng | getline r; print "name"r"-"$0}'
5

This variation on a couple of the other answers does the random string generation outside of awk:

LC_ALL=C tr -dc '[:alnum:]' </dev/urandom | fold -w 6 |
awk '{ getline r <"/dev/stdin"; printf("name%s-%s\n", r, $0) }' file

The tr+fold pipeline generates an endless stream of random six-character strings on the standard input of awk. awk will ignore the standard input if a filename is provided, so these random strings are read by getline from /dev/stdin into the variable r. printf is then used to prefix the lines from the file with the appropriate string.

Given the file

123
abc
@#$

this may produce

nameFI4L1S-123
name5S8Shr-abc
namebRUjzV-@#$
1

Without using awk at all, just simple bash

while read line; do
    printf "name%s-%s\n" \
        "$(tr -dc '[:alnum:]' </dev/urandom|head -c6)" \
        "$line"
done <myfile
1
0
paste <(base64 -w6 /dev/urandom) input.txt | awk 'NF==2{print $1$2} NF!=2{exit}'

Requirements - the input.txt should contain only one column, in other words, it shouldn't have tabs or spaces, because they used as default separator by awk and paste (only tab character) commands. Otherwise, the command must be modified a little bit.

Note: The Base64 alphabet contains + and / characters: Base64 table, if you want only numbers and letters, you can use base32 command - Base32 alphabet.

Input

===my_line_a
===my_line_b
===my_line_c
===my_line_d
===my_line_e

=== characters added for clarity.

Output

LYSdm8===my_line_a
5sSSNt===my_line_b
YVMdkA===my_line_c
3b/nsT===my_line_d
xt/AZO===my_line_e
0

As Inian suggested, the problem with your code is that you're just setting the variable once, not for each line.

If you want, you can probably do this in pure awk without the need to hit an external command repeatedly. Running an external command, whether in system or through redirection, may be slow. (Guessing. I haven't done comparisons. If you do, I'd love to see your results.)

Here's something that prints a different random string at the end of each line, using awk's internal rand() function:

#!/usr/bin/awk -f

function rstring(ln,   out) {
        out=""
        while (ln>0) {
                out=sprintf("%s%c", out, int(rand()*94+33))
                ln--
        }
        return out
}

BEGIN {
        srand()
        len=8
}

{
        r=rstring(len)
        printf("%s%s\n", $0, r)
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .