Comment puis-je ajouter une chaîne aléatoire pour chaque ligne?

12

J'essaie d'ajouter une chaîne aléatoire pour chaque ligne lors de l'exécution:

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

Avant cela, la chaîne aléatoire est générée:

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

Le problème est qu'il affichera la même chaîne aléatoire pour chaque ligne:

nameGQz3Ek-
nameGQz3Ek-
nameGQz3Ek-

Que dois-je faire pour obtenir une chaîne aléatoire différente pour chaque ligne?

user134969
la source
Au lieu d'une certaine variation de tr -dc '[:alnum:]' </dev/urandom | head -c 6, il serait plus simple et plus efficace à utiliser pwgen -s 6 1, ou mieux encore pwgen -s 6 $(wc -l myfile)vous donnerait exactement toutes les chaînes aléatoires dont vous avez besoin, en une seule fois.
user1404316

Réponses:

9

Avec la fonction awk system() :

Échantillon input.txt:

a
b
c

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

Exemple de sortie:

nameSDbQ7T-a
nameAliHY0-b
nameDUGP2S-c

system(command)
Exécutez la commande du système d'exploitation, commandpuis revenez au programme awk

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

RomanPerekhrest
la source
Bien, mais pourquoi je reçois tr: write error: Broken pipe?
user134969
@ user134969, cela fonctionne bien. Assurez-vous que vous n'avez commis aucune erreur sur la ligne de commande
RomanPerekhrest
9

Ne pensez-vous pas que c'est un peu évident? Vous générez juste une chaîne aléatoire une fois et la stockez dans une ranvariable et l'utilisez pour toutes les lignes!

Utilisation getlinedans une variable d'un tuyau

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

Lorsque vous utilisez command | getline var, la sortie de la commande est envoyée via un canal vers getline()et dans la variable var.

Notez également qu'un canal ouvert pour la sortie se awksouvient de la commande qui lui est associée et que les écritures suivantes sur la commande sont ajoutées aux écritures précédentes. Nous devons close()appeler explicitement la commande pour éviter cela.

Si les guillemets simples imbriqués dans le str_generatorsont à l'origine d'un problème, remplacez-le par son équivalent octal ( \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
Inian
la source
8

L'exécution d'une instance de tr -dc '[:alnum:]' </dev/urandom | head -c 6par ligne d'entrée serait contre-productive, vous feriez mieux de le faire:

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

Si votre entrée ne contient pas ni guillemets simples guillemets obliques, vous pouvez aussi utiliser m4l » mkstemp():

<input sed "s/.*/mkstemp(name)\`&'/" | m4
Stéphane Chazelas
la source
4

Cette variation sur quelques autres réponses fait la génération de chaînes aléatoires en dehors de 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

Le pipeline tr+ foldgénère un flux sans fin de chaînes aléatoires de six caractères sur l'entrée standard de awk. awkignorera l'entrée standard si un nom de fichier est fourni, donc ces chaînes aléatoires sont lues par getlinefrom /dev/stdindans la variable r. printfest ensuite utilisé pour préfixer les lignes du fichier avec la chaîne appropriée.

Compte tenu du dossier

123
abc
@#$

cela peut produire

nameFI4L1S-123
name5S8Shr-abc
namebRUjzV-@#$
Kusalananda
la source
1

Sans utiliser awk du tout, c'est simple bash

while read line; do
    printf "name%s-%s\n" \
        "$(tr -dc '[:alnum:]' </dev/urandom|head -c6)" \
        "$line"
done <myfile
Riches
la source
1
Le problème est que vous pouvez corrompre les données lues dans le fichier. Voir unix.stackexchange.com/questions/209123/…
Kusalananda
0
paste <(base64 -w6 /dev/urandom) input.txt | awk 'NF==2{print $1$2} NF!=2{exit}'

Exigences - le fichier input.txt ne doit contenir qu'une seule colonne, en d'autres termes, il ne doit pas avoir de tabulations ou d'espaces, car ils sont utilisés comme séparateur par défaut par les commandes awket paste(uniquement les caractères de tabulation). Sinon, la commande doit être modifiée un peu.

Remarque: L' alphabet Base64 contient +et des /caractères: Tableau Base64 , si vous ne voulez que des chiffres et des lettres, vous pouvez utiliser la base32commande - Alphabet Base32 .

Contribution

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

=== caractères ajoutés pour plus de clarté.

Production

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