仅使用 bash 从目录中抓取随机文件

Grab random files from a directory using just bash

我想创建一个 bash 脚本,它可以抓取符合特定 glob 模式的文件并将它们复制到另一个文件夹,例如

$foo\ 
a.txt
b.txt
c.txt
e.txt
f.txt
g.txt 

运行 请求 2 个文件的脚本我会得到

$bar\ 
c.txt 
f.txt 

我不确定 bash 是否有随机数生成器以及如何使用它从列表中提取。该目录也很大(超过 100K),因此一些 glob 内容将不起作用。

提前致谢

试试这个:

#!/bin/bash

sourcedir="files"

# Arguments processing
if [[ $# -ne 1 ]]
then
    echo "Usage: random_files.bash NUMBER-OF-FILES"
    echo "       NUMBER-OF-FILES: how many random files to select"
    exit 0
else
    numberoffiles=""
fi

# Validations
listoffiles=()
while IFS='' read -r line; do listoffiles+=("$line"); done < <(find "$sourcedir" -type f -print)
totalnumberoffiles=${#listoffiles[@]}

# loop on the number of files the user wanted
for (( i=1; i<=numberoffiles; i++ ))
do
    # Select a random number between 0 and $totalnumberoffiles
    randomnumber=$(( RANDOM % totalnumberoffiles ))
    echo "${listoffiles[$randomnumber]}"
done
  • 用文件名构建数组
  • 从 0 到数组大小的随机数
  • 显示该索引处的文件名
  • 如果你想随机 select 多个文件
  • ,我内置了一个循环
  • 你可以为文件的位置设置另一个参数,我在这里硬编码了。

另一种方法,如果由于同一目录中的文件太多而失败,可以是:

#!/bin/bash

sourcedir="files"

# Arguments processing
if [[ $# -ne 1 ]]
then
    echo "Usage: random_files.bash NUMBER-OF-FILES"
    echo "       NUMBER-OF-FILES: how many random files to select"
    exit 0
else
    numberoffiles=""
fi

# Validations
find "$sourcedir" -type f -print >list.txt
totalnumberoffiles=$(wc -l list.txt | awk '{print }')

# loop on the number of files the user wanted
for (( i=1; i<=numberoffiles; i++ ))
do
    # Select a random number between 1 and $totalnumberoffiles
    randomnumber=$(( ( RANDOM % totalnumberoffiles ) + 1 ))
    sed -n "${randomnumber}p" list.txt
done

/bin/rm -f list.txt
  • 构建文件列表,使每个文件名都在一行上
  • select一个随机数
  • 在那一个中​​,随机数必须为 +1,因为行数从 1 开始,而不是像在数组中那样从 0 开始。
  • 使用sed打印文件列表中的随机行

使用 GNU shuf,这会将给定源目录中与给定 glob 模式匹配的 N 个随机文件复制到给定目标目录。

#!/bin/bash -e

shopt -s failglob

n=${1:?} glob=${2:?} source=${3:?} dest=${4:?}
declare -i rand
IFS=

[[ -d "$source" ]]
[[ -d "$dest" && -w "$dest" ]]

cd "$dest"
dest=$PWD
cd "$OLDPWD"
cd "$source"

printf '%s[=10=]' $glob |
shuf -zn "$n" |
xargs -0 cp -t "$dest"

像这样使用:

./cp-rand 2 '?.txt' /source/dir /dest/dir
  • 这适用于包含数千个文件的目录。 xargs 将管理像 ARG_MAX.

    这样的限制
  • $glob,未加引号,进行文件名扩展(glob 扩展)。因为 IFS 是空的,所以 glob 模式可以包含空格。

  • 匹配sub-directories将导致cp出错并过早退出(某些文件可能已被复制)。 cp -r 允许 sub-directories.

  • cp -t targetxargs -0 不是 POSIX.

  • 请注意,对列表中的 select 个文件使用随机数会导致重复,因此您复制的文件可能少于 N 个。因此使用 GNU shuf.