如何在bash中列出具有多个条件的文件并选择一个随机条件?

时间:2018-10-18 20:31:42

标签: bash shell directory

我有一个具有这种性质的文件目录:

1985-08-28_state.txt  2001-04-29_state.txt  2016-12-29_state.txt
1985-08-29_state.txt  2001-04-30_state.txt  2016-12-30_state.txt
1985-08-30_state.txt  2001-05-01_state.txt  2016-12-31_state.txt

我想选择5月至6月的所有文件,然后从列表中随机选择一个文件。

#!/bin/bash -u

states_path=./daily_states/
date="*-05-*_state.txt *-06-*_state.txt" #Patterns for May-June files
statefile=`ls ${states_path}/$date| shuf -n 1`

printf "$statefile \n"

,但这不能访问第二个参数。

警告

ls: cannot access *-06-*_state.txt: No such file or directory

为什么会这样,我该如何解决?

我愿意采取任何其他方式。

替代答案

我想到了另一种方法。不是最优雅的解决方案。但是我想这行得通吗?

states_path=/daily_states/

statefile[0]=`ls ${states_path}/*-05-*_state.txt | shuf -n 1`
statefile[1]=`ls ${states_path}/*-06-*_state.txt | shuf -n 1`

randstate=$(($RANDOM % 2))

echo "${statefile[$randstate]}"

2 个答案:

答案 0 :(得分:1)

让我们看看您的变量如何扩展。您设置:

date="*-05-*_state.txt *-06-*_state.txt"

然后使用命令输出设置$statefile

ls ${states_path}/*-05-*_state.txt *-06-*_state.txt| shuf -n 1

现在您看到问题了吗?

一种更好的处理方式可能是使用数组存储模式,而使用另一个数组收集文件名,因为parsing ls is problematic

#!/usr/bin/env bash

states_path=./daily_states/
patterns=("*-05-*_state.txt" "*-06-*_state.txt")

a=()                    # initialize an empty array

shopt -s nullglob       # if no expansion occurs, expand to null

# Step through your patterns...
for monthpat in "${patterns[@]}"; do
  # And add files matching the pattern to the array.
  a+=( $states_path/$monthpat )
done

# Print the list
declare -p a
# or if you prefer,
printf '%s\n' "${a[@]}"

# Or just print one random entry:
printf 'random: %s\n' "${a[ $(( $RANDOM % ${#a[@]} )) ]}"

请注意,我不使用shuf,因为它不是bash的一部分,并且在使用bash的操作系统(FreeBSD和macOS)上不可用。


如果您知道只对这两个月的文件感兴趣,则可以将它们表示为一个文件。因此:

a=( $states_path/*-0[56]-*_state.txt )
printf '%s\n' "${a[$(($RANDOM%${#a[@]}))]}"

答案 1 :(得分:1)

您的简短解决方案存在一些问题:

  • 解析ls的输出。带有空格等的路径可能会引起问题。
  • 所选文件的分发可能不统一。如果第一个glob返回100个文件,第二个glob返回一个文件,则从第二个glob获取一个文件的机会要比从第一个glob获取特定文件的机会高得多。

这里是解决这些问题的替代方法,而且更短:

 shuf -en1 daily_states/*-05-*_state.txt daily_states/*-06-*_state.txt

两个小球也可以如下组合。

 shuf -en1 daily_states/*-0{5,6}-*_state.txt

如ghoti所述,请考虑使用shopt -s nullglob -比后悔更安全。