我怎么能选择在bash目录随机文件?我怎么能选择在bash目录随机文件?(How can I sel

2019-05-13 08:52发布

我有大约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.txtfilename2.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的没有那种-RSHUF命令,所以我需要一个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]”



文章来源: How can I select random files from a directory in bash?
标签: bash random