J'ai un répertoire avec environ 2000 fichiers. Comment puis-je sélectionner un échantillon aléatoire de fichiers N
en utilisant un script bash ou une liste de commandes canalisées?Comment puis-je sélectionner des fichiers aléatoires à partir d'un répertoire dans bash?
Répondre
Voici un script qui utilise l'option GNU est un peu aléatoire:
ls |sort -R |tail -$N |while read file; do
# Something involving $file, or you can leave
# off the while to just get the filenames
done
Cool, ne connaissait pas le sort -R; J'ai déjà utilisé bogosort :-p – alex
sort: option invalide - R Essayez 'sort --help 'pour plus d'informations. –
Ne semble pas fonctionner pour les fichiers contenant des espaces. – Houshalter
Voici quelques possibilités qui ne compilent pas la sortie de ls
et qui sont 100% sûr en ce qui concerne les fichiers avec des espaces et des symboles amusants dans leur prénom. Tous vont remplir un tableau randf
avec une liste de fichiers aléatoires. Ce tableau est facilement imprimé avec printf '%s\n' "${randf[@]}"
si nécessaire.
Celui-ci sera peut-être sortie plusieurs fois le même fichier, et
N
est nécessaire de connaître à l'avance. Ici, j'ai choisi N = 42.a=(*) randf=("${a[RANDOM%${#a[@]}]"{1..42}"}")
Cette fonctionnalité n'est pas très bien documentée.
Si N n'est pas connu à l'avance, mais que vous avez vraiment aimé la possibilité précédente, vous pouvez utiliser
eval
. Mais c'est mal, et vous devez vraiment vous assurer queN
ne vient pas directement de la saisie de l'utilisateur sans être soigneusement vérifié!N=42 a=(*) eval randf=(\"\${a[RANDOM%\${#a[@]}]\"\{1..$N\}\"}\")
Je n'aime pas personnellement
eval
et donc cette réponse!Le même en utilisant une méthode plus simple (une boucle):
N=42 a=(*) randf=() for((i=0;i<N;++i)); do randf+=("${a[RANDOM%${#a[@]}]}") done
Si vous ne voulez pas avoir peut-être plusieurs fois le même fichier:
N=42 a=(*) randf=() for((i=0;i<N && ${#a[@]};++i)); do ((j=RANDOM%${#a[@]})) randf+=("${a[j]}") a=("${a[@]:0:j}" "${a[@]:j+1}") done
Note. Ceci est une réponse tardive à un ancien message, mais la réponse acceptée renvoie à une page externe qui montre une pratique terrible, et l'autre réponse n'est pas beaucoup mieux car elle analyse également la sortie de ls
. Un commentaire à la réponse acceptée indique une excellente réponse de Lhunath qui montre évidemment de bonnes pratiques, mais ne répond pas exactement au PO.
Première et deuxième "mauvaise substitution" produite; il n'aimait pas la partie '" {1..42} "' laissant un "1 En outre, '$ RANDOM' est seulement 15 bits et la méthode ne fonctionnera pas avec plus de 32767 fichiers à choisir. –
Vous pouvez utiliser shuf
(à partir du package GNU coreutils) pour cela. Il suffit de nourrir une liste de noms de fichiers et de lui demander de retourner la première ligne d'une permutation aléatoire:
ls dirname | shuf -n 1
# probably faster and more flexible:
find dirname -type f | shuf -n 1
# etc..
Régler la valeur -n, --head-count=COUNT
pour retourner le nombre de lignes voulu. Par exemple, pour revenir 5 noms de fichiers aléatoires que vous utilisez:
find dirname -type f | shuf -n 5
OP voulait sélectionner «N» des fichiers aléatoires, donc en utilisant «1» est un peu trompeur. – aioobe
Mais 'N' peut être' 1' – CousinCocaine
Si vous avez des noms de fichiers avec newlines: 'find dirname -type f -print0 | shuf -zn1' – Hitechcomputergeek
C'est le seul script que je peux apprendre à jouer agréable avec bash sur MacOS.Je combiné et des extraits édités des deux liens suivants:
ls command: how can I get a recursive full-path listing, one line per file?
#!/bin/bash
# Reads a given directory and picks a random file.
# The directory you want to use. You could use "$1" instead if you
# wanted to parametrize it.
DIR="/path/to/"
# DIR="$1"
# Internal Field Separator set to newline, so file names with
# spaces do not break our script.
IFS='
'
if [[ -d "${DIR}" ]]
then
# Runs ls on the given dir, and dumps the output into a matrix,
# it uses the new lines character as a field delimiter, as explained above.
# file_matrix=($(ls -LR "${DIR}"))
file_matrix=($(ls -R $DIR | awk '; /:$/&&f{s=$0;f=0}; /:$/&&!f{sub(/:$/,"");s=$0;f=1;next}; NF&&f{ print s"/"$0 }'))
num_files=${#file_matrix[*]}
# This is the command you want to run on a random file.
# Change "ls -l" by anything you want, it's just an example.
ls -l "${file_matrix[$((RANDOM%num_files))]}"
fi
exit 0
J'utilise ceci: il utilise un fichier temporaire, mais va profondément dans un répertoire jusqu'à ce qu'il trouve un fichier régulier et retour il.
# find for a quasi-random file in a directory tree:
# directory to start search from:
ROOT="/";
tmp=/tmp/mytempfile
TARGET="$ROOT"
FILE="";
n=
r=
while [ -e "$TARGET" ]; do
TARGET="$(readlink -f "${TARGET}/$FILE")" ;
if [ -d "$TARGET" ]; then
ls -1 "$TARGET" 2> /dev/null > $tmp || break;
n=$(cat $tmp | wc -l);
if [ $n != 0 ]; then
FILE=$(shuf -n 1 $tmp)
# or if you dont have/want to use shuf:
# r=$(($RANDOM % $n)) ;
# FILE=$(tail -n +$(($r + 1)) $tmp | head -n 1);
fi ;
else
if [ -f "$TARGET" ] ; then
rm -f $tmp
echo $TARGET
break;
else
# is not a regular file, restart:
TARGET="$ROOT"
FILE=""
fi
fi
done;
Si vous avez installé Python (fonctionne soit avec Python 2 ou Python 3):
Pour sélectionner un fichier (ou d'une ligne à partir d'une commande arbitraire), utilisez
ls -1 | python -c "import sys; import random; print(random.choice(sys.stdin.readlines()).rstrip())"
Pour sélectionner N
fichiers/lignes, l'utilisation (note N
est à la fin de la commande, remplacer par un numéro)
ls -1 | python -c "import sys; import random; print(''.join(random.sample(sys.stdin.readlines(), int(sys.argv[1]))).rstrip())" N
Cela ne fonctionne pas si votre nom de fichier contient des retours à la ligne. – bfontaine
Ceci est une réponse encore plus tardive à la réponse tardive de @ gniourf_gniourf, que je viens de mettre à jour parce que c'est de loin la meilleure réponse, deux fois plus. (Une fois pour éviter eval
et une fois pour la gestion sûre des noms de fichier.)
Mais il m'a fallu quelques minutes pour démêler la (les) caractéristique (s) "pas très bien documentée (s)" que cette réponse utilise. Si vos compétences Bash sont suffisamment solides pour que vous voyiez immédiatement comment cela fonctionne, alors passez ce commentaire. Mais je ne l'ai pas fait, et après l'avoir démêlé, je pense que ça vaut la peine d'expliquer.
Fonctionnalité # 1 est la propre globalisation de fichier du shell. a=(*)
crée un tableau, $a
, dont les membres sont les fichiers du répertoire en cours. Bash comprend toutes les bizarreries des noms de fichiers, de sorte que la liste est garantie correcte, garanti échappé, etc Pas besoin de s'inquiéter de l'analyse correcte des noms de fichiers textuels retournés par ls
.
La caractéristique # 2 est Bash parameter expansions pour arrays, une imbriquée dans une autre. Cela commence par ${#ARRAY[@]}
, qui s'étend à la longueur de $ARRAY
. Cette extension est ensuite utilisée pour l'indice du tableau. La façon standard de trouver un nombre aléatoire entre 1 et N est de prendre la valeur du nombre aléatoire modulo N. Nous voulons un nombre aléatoire entre 0 et la longueur de notre tableau. Voici l'approche, coupée en deux par souci de clarté:
LENGTH=${#ARRAY[@]}
RANDOM=${a[RANDOM%$LENGTH]}
Mais cette solution, il le fait dans une seule ligne, en supprimant l'affectation des variables inutiles.
La caractéristique # 3 est Bash brace expansion, bien que je dois avouer que je ne comprends pas entièrement. L'expansion de l'accolade est utilisée, 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 sous-couche ci-dessus, "${a[RANDOM%${#a[@]}]"{1..42}"}"
, utilise cette astuce pour produire 42 expansions séparées. L'expansion de l'accolade place un seul chiffre entre le ]
et le }
, qui, au début, je pensais que l'indice était le tableau, mais si c'est le cas, il serait précédé d'un deux-points.(Il aurait également renvoyé 42 éléments consécutifs d'un endroit aléatoire dans le tableau, ce qui n'est pas du tout la même chose que de renvoyer 42 éléments aléatoires du tableau.) Je pense que c'est juste que le shell exécute l'expansion 42 fois, retournant 42 éléments aléatoires du tableau. (Mais si quelqu'un peut l'expliquer plus complètement, j'aimerais l'entendre.)
La raison pour laquelle N doit être codé en dur (42) est que l'expansion de l'accolade se produit avant l'expansion de la variable.
Enfin, voici Feature # 4, si vous voulez faire récursive pour une hiérarchie de répertoires:
shopt -s globstar
a=(**)
Cela tourne sur un shell option qui provoque **
pour correspondre récursive. Votre tableau $a
contient maintenant tous les fichiers de la hiérarchie entière.
Que diriez-vous d'une solution Perl légèrement retouchée de M. Kang ici:
How can I shuffle the lines of a text file on the Unix command line or in a shell script?
$ ls | perl -MList :: Util = shuffle -e '@lines = shuffle (<>); imprimer @lines [0..4] »
Une solution simple pour sélectionner 5
fichiers aléatoires en avoiding to parse ls. Il fonctionne également avec les fichiers contenant des espaces, des sauts de ligne et autres caractères spéciaux:
shuf -ezn 5 * | xargs -0 -n1 echo
Remplacer echo
avec la commande que vous souhaitez exécuter pour vos fichiers.
bien, le tube + 'read' n'a-t-il pas les mêmes problèmes que l'analyse de' ls'? à savoir, il lit ligne par ligne, de sorte qu'il ne fonctionne pas pour les fichiers avec des nouvelles lignes dans leur nom –
Vous avez raison. Ma solution précédente ne fonctionnait pas pour les noms de fichiers contenant des retours à la ligne et se brisait probablement sur d'autres avec certains caractères spéciaux. J'ai mis à jour ma réponse pour utiliser null-termination au lieu de newlines. – scai
ls | shuf -n 10 # ten random files
Vous ne devriez pas compter sur la sortie de 'ls'. Cela ne fonctionnera pas si, par ex. un nom de fichier contient des nouvelles lignes. – bfontaine
@bfontaine vous semblez hanté par les nouvelles lignes dans les noms de fichiers :). Sont-ils vraiment si commun? En d'autres termes, existe-t-il un outil qui crée des fichiers avec des nouvelles lignes dans leur nom? En tant qu'utilisateur, il est très difficile de créer un tel nom de fichier. Idem pour les fichiers provenant d'Internet –
@CiprianTomoiaga Voilà un exemple des problèmes que vous pourriez rencontrer. 'ls' n'est pas garanti pour vous donner des noms de fichiers" propres "donc vous ne devriez pas compter dessus, point final. Le fait que ces problèmes soient rares ou inhabituels ne change pas le problème; surtout étant donné qu'il existe de meilleures solutions pour cela. – bfontaine
MacOS ne pas les tri-R et SHUF commandes, donc je besoin d'une bash seule solution qui randomizes tous les fichiers sans doublons et n'a pas trouvé ici. Cette solution est similaire à la solution # 4 de gniourf_gniourf, mais j'espère ajouter de meilleurs commentaires.
Le script devrait être facile à modifier pour arrêter après N échantillons en utilisant un compteur avec if, ou gniourf_gniourf pour la boucle avec N. $ RANDOM est limité à ~ 32000 fichiers, mais cela devrait le faire dans la plupart des cas.
#!/bin/bash
array=(*) # this is the array of files to shuffle
# echo ${array[@]}
for dummy in "${array[@]}"; do # do loop length(array) times; once for each file
length=${#array[@]}
randomi=$(($RANDOM % $length)) # select a random index
filename=${array[$randomi]}
echo "Processing: '$filename'" # do something with the file
unset -v "array[$randomi]" # set the element at index $randomi to NULL
array=("${array[@]}") # remove NULL elements introduced by unset; copy array
done
- 1. Comment sélectionner des fichiers dans un dossier?
- 2. Comment faire quelque chose à tous les fichiers dans un répertoire en utilisant bash?
- 3. Comment faire pour supprimer des caractères spécifiques à partir de noms de fichiers en utilisant BASH
- 4. bash scripting.Copier des fichiers sans écraser
- 5. bash: Exécuter un autre programme dans le répertoire courant en cours d'exécution à partir du chemin
- 6. Script shell (mac): Comment télécharger des fichiers à partir d'un répertoire en utilisant wget et une expression régulière?
- 7. Comment sélectionner N lignes aléatoires en utilisant SQL pur?
- 8. Comment utiliser anything.el pour ouvrir des fichiers à partir d'un certain répertoire
- 9. Comment déboguer des plantages aléatoires?
- 10. Comment déplacer par programme des fichiers dans un répertoire WebDAV
- 11. comment créer des fichiers hbm à partir de fichiers java?
- 12. Comment générer des identités aléatoires?
- 13. Comment protéger les fichiers téléchargeables dans un répertoire distant à partir d'utilisateurs non-premium (en php?)
- 14. Script Bash, correspondre à des dates comme?
- 15. Comment stocker des valeurs persistantes de fichiers dans un répertoire?
- 16. impression des noms de répertoires et ne fichiers (BASH)
- 17. Erreurs aléatoires lors du téléchargement de fichiers à partir du point de partage
- 18. Comment explorer les classes chargées à partir des fichiers JAR?
- 19. achèvement bash pour certains types de fichiers dans un répertoire spécial
- 20. Comment sélectionner des valeurs dans une plage d'index fourni à partir d'une liste à l'aide LINQ
- 21. Comment autoriser l'utilisateur à sélectionner plusieurs fichiers à télécharger?
- 22. Activation des notifications KDE 4 à partir de scripts bash
- 23. Bash: comment parcourir la structure du répertoire et exécuter des commandes?
- 24. Bash: Comment vérifier si certains fichiers existent?
- 25. affichant des nombres aléatoires
- 26. Comment exécutez-vous SQL à partir d'un script bash?
- 27. Comment obtenir une liste de fichiers dans C# à partir d'un chemin de répertoire contenant des caractères génériques?
- 28. Comment ajouter des fichiers et des répertoires à un fichier zip sans le répertoire racine?
- 29. Sélectionner des lignes aléatoires mais sans doublons de valeurs d'une colonne
- 30. Comment mettre à jour un champ avec des données aléatoires?
également une bonne réponse à Unix et Linux: http://unix.stackexchange.com/a/38344/24170 –
'ls | shuf -n 5' [Source de Unix Stackexchange] (http://unix.stackexchange.com/a/48477/14993) – jgomo3
Similaire: https://stackoverflow.com/questions/2153882/how-can-i-shuffle -les-lignes-d'un-fichier-texte-sur-l'unix-command-line-or-in-a-shel – AAAfarmclub