J'essaie d'écrire un script shell. L'idée est de sélectionner une seule ligne au hasard dans un fichier texte et de l'afficher en tant que notification de bureau Ubuntu.
Mais je veux que différentes lignes soient sélectionnées à chaque fois que j'exécute le script. Y a-t-il une solution pour ce faire? Je ne veux pas le script entier. Juste cette chose simple seulement.
scripts
text-processing
Anandu M Das
la source
la source
Réponses:
Vous pouvez utiliser l'
shuf
utilitaire pour imprimer des lignes aléatoires à partir d'un fichier-n
: nombre de lignes à imprimerExemples:
la source
n
indiquer le nombre de lignes à imprimer. (c'est-à-dire si vous ne voulez qu'une seule ligne ou deux lignes). Pas le numéro de ligne (c'est-à-dire la première ligne de la deuxième ligne)date +%S
) dans une variable x, puis sélectionner cette xième ligne en utilisant les commandeshead
ettail
du fichier texte. Quoi qu'il en soit, votre méthode est plus simple. Mercishuf
est dans coreutils, il est donc disponible par défaut. Remarque: il charge le fichier d'entrée en mémoire. Il existe un algorithme efficace qui n'en a pas besoin .Vous pouvez également utiliser la
sort
commande pour obtenir une ligne aléatoire à partir du fichier.la source
sort -R
produit un résultat différent deshuf -n1
ouselect-random
s'il y a des lignes en double dans l'entrée. Voir le commentaire de @ EliahKagan .Juste pour le plaisir, voici un solution pure bash qui n'utilise pas
shuf
,sort
,wc
,sed
,head
,tail
ou tout autre outils externes.Le seul avantage par rapport à la
shuf
variante est qu'elle est légèrement plus rapide, car elle est pure bash. Sur ma machine, pour un fichier de 1000 lignes, lashuf
variante prend environ 0,1 seconde, tandis que le script suivant prend environ 0,01 seconde;) Donc, alors queshuf
c'est la variante la plus simple et la plus courte, c'est plus rapide.En toute honnêteté, j'irais toujours pour la
shuf
solution, à moins que la haute efficacité ne soit une préoccupation importante.la source
shuf
est bien meilleure de toute façon. En y réfléchissant, je ne pense pas que le bash pur soit en fait plus efficace que l'utilisationshuf
, comme je l'ai écrit précédemment. Il peut y avoir la moindre surcharge (constante) lors du lancement d'un outil externe, mais il s'exécutera plus rapidement que bash interprété. Alors, çashuf
évolue certainement mieux. Alors disons que le script a un but éducatif: c'est agréable de voir que cela peut être fait;)shuf
spécifique à GNU Coreutils (par exemple, pas dans FreeBSD 10.0).sort -R
est portable, mais résout un problème différent (lié): les chaînes apparaissant comme plusieurs lignes ont une probabilité égale à celles n'apparaissant qu'une seule fois. (Bien sûr,wc
et d'autres utilitaires pourraient encore être utilisés.) Je pense que la principale limitation ici est que cela ne choisit jamais rien après la 32768e ligne (et devient moins aléatoire un peu plus tôt).$((RANDOM<<15|RANDOM))
est en 0..2 ^ 30-1. @JFSebastian Ce n'estshuf
pas le cassort -R
, ce qui biaise vers des entrées plus fréquentes. Mettreshuf -n 1
en placesort -R | head -n1
et comparer. (Btw 10 ^ 3 itérations est plus rapide que 10 ^ 6 et encore assez pour montrer la différence.) Voir aussi une démo plus grossière et plus visuelle et ce peu de bêtise montrant qu'il fonctionne sur de grandes entrées où toutes les cordes sont à haute fréquence .dieharder
semble être tous des zéros. En supposant que ce n'est pas simplement une étrange erreur de ma part, cela expliquerait certainement pourquoi ce n'est pas aléatoire! Obtenez-vous de bonnes données si vous exécutezwhile echo $(( RANDOM << 17 | RANDOM << 2 | RANDOM >> 13 )); do :; done | perl -ne 'print pack "I>"' > out
pendant un certain temps, puis examinez le contenu d'out
un éditeur hexadécimal? (Ou voir cependant autre que vous aimez.) Je reçois tous les zéros, etRANDOM
n'est pas le coupable: je reçois tous les zéros quand je remplacerai$(( RANDOM << 17 | RANDOM << 2 | RANDOM >> 13 ))
avec100
, aussi.Disons que vous avez un fichier
notifications.txt
. Nous devons compter le nombre total de lignes, pour déterminer la plage du générateur aléatoire:Permet d'écrire dans une variable:
Maintenant, pour générer un nombre de
0
à$LINE
nous utiliserons uneRANDOM
variable.Permet de l'écrire dans une variable:
Il ne nous reste plus qu'à imprimer ce numéro de ligne:
À propos de RANDOM:
Assurez-vous que votre fichier comporte moins de 32767 numéros de ligne. Voyez ceci si vous avez besoin d'un plus grand générateur aléatoire qui fonctionne hors de la boîte.
Exemple:
la source
LINES=$(wc -l < file.txt); R_LINE=$((RANDOM % LINES)); sed -n "${R_LINE}p" file.txt
$RANDOM % n
peut fausser votre distribution aléatoire même si$RANDOM
elle est correcte% n
à un nombre aléatoire.Voici un script Python qui sélectionne une ligne aléatoire dans les fichiers d'entrée ou stdin:
L'algorithme est O (n) -heure, O (1) -espace. Il fonctionne pour les fichiers de plus de 32 767 lignes. Il ne charge pas les fichiers d'entrée en mémoire. Il lit chaque ligne d'entrée exactement une fois, c'est-à-dire que vous pouvez y canaliser un contenu arbitraire de grande taille (mais fini). Voici une explication de l'algorithme .
la source
Je suis impressionné par le travail que Malte Skoruppa et d'autres ont fait, mais voici une manière beaucoup plus simple de «pur bash»:
Comme certains l'ont noté, $ RANDOM n'est pas aléatoire. Cependant, la limite de taille de fichier de 32 767 lignes est dépassée en enchaînant $ RANDOM ensemble selon les besoins.
la source