我有大约2000文件的目录。 如何选择的随机样本N
通过使用一个bash脚本或者管道命令的列表文件?
Answer 1:
下面是一个使用GNU的排序是随机选择的脚本:
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
Answer 2:
您可以使用shuf
为(从GNU coreutils软件包)。 只要给它的文件名列表,并要求它从一个随机排列返回的第一行:
ls dirname | shuf -n 1
# probably faster and more flexible:
find dirname -type f | shuf -n 1
# etc..
调整-n, --head-count=COUNT
值返回想要的行数。 例如,返回5页随机的文件名可以使用:
find dirname -type f | shuf -n 5
Answer 3:
这里是不解析的输出几种可能性ls
和是100%安全的关于与他们的名字空间和有趣的符号文件。 他们都将填充数组randf
与随机文件的列表。 这个阵列被容易地印刷有printf '%s\n' "${randf[@]}"
如果需要的话。
这一个将可能输出相同的文件几次,
N
需要预先已知的。 这里我选择N = 42。a=( * ) randf=( "${a[RANDOM%${#a[@]}]"{1..42}"}" )
这个功能是不是非常有据可查。
如果N是事先不知道,但你真的喜欢以前的可能性,你可以使用
eval
。 但它是邪恶的,你必须真正确保N
并不直接从用户输入而不被彻底检查来了!N=42 a=( * ) eval randf=( \"\${a[RANDOM%\${#a[@]}]\"\{1..$N\}\"}\" )
我个人不喜欢
eval
,因此这个答案!相同的使用更直接的方法(一个循环):
N=42 a=( * ) randf=() for((i=0;i<N;++i)); do randf+=( "${a[RANDOM%${#a[@]}]}" ) done
如果你不想有可能多次相同的文件:
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
注 。 这是一个迟到的答案旧的文章,但接受的答案链接到显示可怕的外部页bash的实践,对方的回答是不是要好得多,因为它也解析的输出ls
。 以接受的答案点 - 评Lhunath一个很好的答案,明显显示出良好的做法,但并不完全回答OP。
Answer 4:
ls | shuf -n 10 # ten random files
Answer 5:
用于选择一个简单的解决5
随机文件,同时避免解析LS 。 它还可以与含有空格,换行和其他特殊字符的文件:
shuf -ezn 5 * | xargs -0 -n1 echo
更换echo
与您要执行的文件的命令。
Answer 6:
如果你已经安装了Python(带有Python的2或Python 3作品):
要选择一个文件(或线从任意命令)时,使用
ls -1 | python -c "import sys; import random; print(random.choice(sys.stdin.readlines()).rstrip())"
要选择N
文件/线,使用(注意N
是在命令结束时,由若干替换此)
ls -1 | python -c "import sys; import random; print(''.join(random.sample(sys.stdin.readlines(), int(sys.argv[1]))).rstrip())" N
Answer 7:
这是@ gniourf_gniourf已故的答案,我只是upvoted,因为它是迄今为止最好的答案,在两次甚至后来的响应。 (一旦避免eval
一次安全文件名的处理。)
但我花了几分钟的时间来解开“没有很好的记录”功能(S)这个答案使用。 如果你击技能是不够扎实,你看到它立即如何工作,然后跳过此评论。 但我没有,并且具有拆散它,我认为这是值得向大家解释。
特征#1是shell自己的文件寻找。 a=(*)
创建一个数组, $a
,其成员是在当前目录中的文件。 巴什理解文件名的所有weirdnesses,所以该名单是保证正确,保证逃过等无需有关正确担心解析由返回文本文件名ls
。
功能#2是击参数扩展为阵列 ,一个嵌套在另一个。 这将启动与${#ARRAY[@]}
其扩展至长度$ARRAY
。
然后,该膨胀被用于下标数组。 该标准的方式来寻找随机数1之间,N是拿我们希望从0到我们的数组的长度的随机数的随机数模N的值。 这里的方法,分为两行清晰的缘故:
LENGTH=${#ARRAY[@]}
RANDOM=${a[RANDOM%$LENGTH]}
但是这种解决方案确实它在一个单一的线,在去除不必要的变量赋值。
功能#3是猛砸括号扩展 ,虽然我不得不承认,我不完全理解它。 括号扩展使用,例如,产生的25个文件命名列表filename1.txt
, filename2.txt
等: echo "filename"{1..25}".txt"
。
上述子外壳内的表达, "${a[RANDOM%${#a[@]}]"{1..42}"}"
使用该特技以产生42个单独膨胀。 支架扩张在之间放置一个单一的数字]
和}
,其在第一予想到的是下标数组,但如果是这样,将一个冒号之前。 (这将也从阵列中,这是不是在所有同样的事情,从数组返回42种随机物品随机点返回的连续42项)。我认为它只是让shell中运行扩展42倍,从而返回42随机项从阵列。 (但是,如果有人能更充分地解释,我很想听听吧。)
其原因N具有被硬编码(42)是可变的膨胀之前括号扩展发生。
最后,这里的功能#4,如果你想为一个目录层次结构递归地做到这一点:
shopt -s globstar
a=( ** )
这将打开一个shell选项 ,导致**
递归匹配。 现在,您的$a
数组包含整个层次结构中的每个文件。
Answer 8:
这是唯一的剧本,我可以得到很好地一起在MacOS庆典。 我结合,并从以下两个链接编辑片段:
ls命令:我怎样才能得到一个递归的完整路径列出每个文件,一行?
http://www.linuxquestions.org/questions/linux-general-1/is-there-a-bash-command-for-picking-a-random-file-678687/
#!/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
Answer 9:
MacOS的没有那种-R和SHUF命令,所以我需要一个bash只随机化的所有文件, 没有重复 ,并没有发现,这里的解决方案。 该解决方案是类似于gniourf_gniourf的解决方案#4,但希望添加了更好的意见。
该脚本应该很容易修改使用一个计数器,如果N个样本后停止,或gniourf_gniourf的与N. $ RANDOM循环限于〜32000页的文件,但应该在大多数情况下做的。
#!/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
Answer 10:
我用这样的:它使用的临时文件,但目录中的深进,直到它找到一个普通的文件,并将其返回。
# 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;
Answer 11:
如果你的文件夹中有多个文件,可以使用下面的命令管道中我发现UNIX stackexchange 。
find /some/dir/ -type f -print0 | xargs -0 shuf -e -n 8 -z | xargs -0 cp -vt /target/dir/
在这里,我想复制的文件,但如果你想别的移动文件或做一些事情,只需要改变,我已经使用了最后一个命令cp
。
Answer 12:
怎么样一个Perl的解决方案从康先生在这里稍微篡改:
我怎样才能在洗牌的Unix命令行或shell脚本的文本文件的行?
$ LS | perl的-MList ::的Util =洗牌-e“@lines =洗牌(<>); 打印@lines [0..4]”