Comment puis-je sélectionner des fichiers aléatoires à partir d'un répertoire en bash?
J'ai un répertoire avec près de 2000 fichiers. Comment puis-je sélectionner un échantillon aléatoire de N
fichiers par le biais de l'aide d'un script bash ou une liste de canalisations d'commandes?
- Également une bonne réponse à Unix&Linux : unix.stackexchange.com/a/38344/24170
ls | shuf -n 5
Source d'Unix Stackexchange- Similaire: stackoverflow.com/questions/2153882/...
Vous devez vous connecter pour publier un commentaire.
Voici un script qui utilise GNU tri aléatoire option:
"$file"
, non illustré, serait sensible à des espaces.Vous pouvez utiliser
shuf
(à partir de la GNU coreutils package) pour que les. Seulement nourrir une liste de noms de fichiers et de lui demander de retourner la première ligne à partir d'une permutation aléatoire:Ajuster la
-n, --head-count=COUNT
de la valeur à retourner le nombre de voulait lignes de. Par exemple, pour revenir à 5 noms de fichiers aléatoires, vous devez utiliser:N
fichiers aléatoires, donc à l'aide d'1
est un peu trompeur.N
peut être1
find dirname -type f -print0 | shuf -zn1
Voici quelques possibilités que ne pas analyser la sortie de
ls
et qui sont sûrs à 100% concernant les fichiers avec les espaces et les symboles drôles dans leur nom. Tous d'entre eux vont remplir un tableaurandf
avec une liste de fichiers aléatoires. Ce tableau est facilement imprimés avecprintf '%s\n' "${randf[@]}"
si nécessaire.Ce sera probablement produit le même fichier plusieurs fois, et
N
doit être connue à l'avance. Ici, j'ai choisi N=42.Cette fonctionnalité n'est pas très bien documenté.
Si N n'est pas connu à l'avance, mais vous avez vraiment aimé le précédent possibilité, vous pouvez utiliser
eval
. Mais c'est un mal, et vous devez vraiment faire en sorte queN
ne vient pas directement de la saisie de l'utilisateur sans être soigneusement vérifié!Personnellement, je aversion
eval
et donc cette réponse!Le même à l'aide d'une méthode simple (une boucle):
Si vous ne voulez pas éventuellement avoir plusieurs fois le même fichier:
Note. C'est une réponse tardive à un vieux post, mais le a accepté de répondre à des liens vers une page externe qui montre terribles bash pratique, et de l'autre la réponse n'est pas beaucoup mieux qu'il analyse également la sortie de
ls
. Un commentaire pour la accepté de répondre à points pour une excellente réponse par Lhunath qui représente évidemment une bonne pratique, mais n'est pas exactement la réponse de l'OP."{1..42}"
partie en laissant une fuite"1"
. Aussi,$RANDOM
est à seulement 15 bits et la méthode ne fonctionnera pas avec plus de 32767 fichiers à choisir.ls
. Cela ne fonctionnera pas si par exemple un nom de fichier contient des retours à la ligne.ls
n'est pas garanti pour vous donner de "nettoyer" les noms de fichier de sorte que vous ne devriez pas compter sur elle, période. Le fait que ces questions sont rares ou inhabituels, ne change pas le problème; en particulier étant donné qu'il existe de meilleures solutions pour cela.ls
peut inclure des répertoires et des lignes vides. Je dirais quelque chose commefind . -type f | shuf -n10
à la place.Une solution simple pour la sélection
5
fichiers aléatoires tandis que en évitant d'analyser ls. Il travaille également avec des fichiers contenant des espaces, retours à la ligne et d'autres caractères spéciaux:Remplacer
echo
avec la commande que vous souhaitez exécuter pour vos fichiers.read
ont les mêmes problèmes que l'analyse dels
? à savoir, elle lit ligne par ligne, de sorte qu'il ne fonctionne pas pour les fichiers avec des sauts de ligne dans leur nomSi vous avez installé Python (fonctionne avec Python 2 et Python 3):
Pour sélectionner un fichier (ou d'une ligne à partir d'une commande arbitraire), l'utilisation
Pour sélectionner
N
fichiers/lignes, utiliser (noteN
est à la fin de la commande, le remplacer par un nombre)C'est encore un peu plus tard réponse à @gniourf_gniourf de la réponse tardive, dont je viens de upvoted parce que c'est de loin la meilleure réponse, à deux reprises. (Une fois pour éviter
eval
et une fois pour la sécurité de nom de fichier de la manipulation.)Mais il m'a fallu quelques minutes pour démêler le "pas très bien documenté" caractéristique(s) cette réponse utilise. Si votre Bash compétences sont assez solide qui vous a vu tout de suite comment il fonctionne, puis passez ce commentaire. Mais je n'ai pas, et d'avoir démêlait il je pense qu'il vaut la peine d'expliquer.
Caractéristique n ° 1 est le shell fichiers d'expansion.
a=(*)
crée un tableau,$a
, dont les membres sont les fichiers dans le répertoire courant. Bash comprend tous les weirdnesses de noms de fichiers, de sorte que la liste est garanti correct, garantie échappé, etc. Pas besoin de s'inquiéter à propos de correctement l'analyse textuelle des noms de fichiers retournés parls
.Caractéristique n ° 2 est Bash paramètre expansions pour les tableaux, imbriqués l'un dans l'autre. Cela commence avec
${#ARRAY[@]}
, qui s'étend de la longueur de$ARRAY
.Que l'expansion est ensuite utilisée pour l'indice du tableau. Le niveau moyen de trouver un nombre au hasard entre 1 et N est de prendre la valeur de nombre aléatoire modulo N. Nous voulons un nombre aléatoire entre 0 et la longueur de notre tableau. Voici la démarche, cassé en deux lignes pour plus de clarté:
Mais cette solution ne permet en une seule ligne, en supprimant l'inutile affectation de variable.
Caractéristique n ° 3 est Bash attelle d'extension, même si je dois avouer que je n'est pas tout à fait le comprendre. Attelle d'extension est utilisé, par exemple, pour générer une liste de 25 fichiers nommés
filename1.txt
,filename2.txt
, etc:echo "filename"{1..25}".txt"
.L'expression à l'intérieur de la shell interne est exécuté ci-dessus,
"${a[RANDOM%${#a[@]}]"{1..42}"}"
, utilise cette astuce pour produire 42 séparer les extensions. L'attelle d'extension des lieux un seul chiffre entre les]
et la}
, au premier abord, je pensais subscripting le tableau, mais si oui il serait précédé par un signe deux-points. (Il aurait également retourné 42 éléments consécutifs à partir d'un endroit aléatoire dans la matrice, ce qui n'est pas du tout la même chose que le retour 42 aléatoire éléments du tableau.) Je pense que c'est juste faire le shell, exécutez la commande expansion 42 fois, ce qui permet de revenir 42 aléatoire des éléments de la matrice. (Mais si quelqu'un peut l'expliquer plus complètement, je serais ravi de l'entendre.)La raison N doit être codé en dur (42) est que l'orthèse d'extension qui se passe avant l'expansion des variables.
Enfin, voici Caractéristique n ° 4, si vous voulez faire cela de façon récursive pour une hiérarchie de répertoire:
Cela tourne sur un option shell qui provoque
**
pour correspondre de manière récursive. Maintenant, votre$a
tableau contient tous les fichiers de l'ensemble de la hiérarchie.C'est le seul script que je peux obtenir pour jouer gentil avec bash sur MacOS. J'ai combiné et édité des extraits de liens suivants:
commande ls: comment puis-je obtenir récursive un chemin complet d'inscription, une ligne par fichier?
http://www.linuxquestions.org/questions/linux-general-1/is-there-a-bash-command-for-picking-a-random-file-678687/
MacOS n'a pas le tri -R et shuf commandes, j'ai donc besoin d'un coup la seule solution que réinitialise tous les fichiers sans doublons et n'a pas trouvé ici. Cette solution est similaire à gniourf_gniourf la solution n ° 4, mais j'espère ajoute des commentaires favorables.
Le script doit être facile à modifier pour s'arrêter après N échantillons à l'aide d'un compteur avec des si, ou gniourf_gniourf pour boucle avec N. $ALÉATOIRE est limité à ~32000 fichiers, mais cela devrait le faire pour la plupart des cas.
Je l'utiliser: il utilise le fichier temporaire, mais va profondément dans un répertoire jusqu'à trouver un fichier et de le retourner.
Si vous avez plus de fichiers dans votre dossier, vous pouvez utiliser le dessous des canalisations de commande que j'ai trouvé dans unix stackexchange.
Ici, je voulais copier les fichiers, mais si vous voulez déplacer des fichiers ou de faire autre chose, il suffit de modifier la dernière commande où j'ai utilisé
cp
.Comment sur Perl solution légèrement trafiqué de M. Kang ici:
Comment puis-je mélanger les lignes d'un fichier texte sur les Unix en ligne de commande ou dans un script shell?