Linux 从args中选择随机条目的更好方法?
我只是想知道,因为我上个月突然想到了这个Linux 从args中选择随机条目的更好方法?,linux,bash,Linux,Bash,我只是想知道,因为我上个月突然想到了这个 #!/usr/bin/bash # Collects all of the args, make sure to seperate with ',' IN="$*" # Takes everything before a ',' and places them each on a single line of tmp file echo $IN | sed 's/,/\n/g' > /tmp/pick.a.random.word.or.phra
#!/usr/bin/bash
# Collects all of the args, make sure to seperate with ','
IN="$*"
# Takes everything before a ',' and places them each on a single line of tmp file
echo $IN | sed 's/,/\n/g' > /tmp/pick.a.random.word.or.phrase
# Obvious vars are obvious
WORDFILE="/tmp/pick.a.random.word.or.phrase"
# Pick only one of the vars
NUMWORDS=1
## Picks a random line from tmp file
#Number of lines in $WORDFILE
tL=`awk 'NF!=0 {++c} END {print c}' $WORDFILE`
# Expand random
RANDOM_CMD='od -vAn -N4 -tu4 /dev/urandom'
for i in `seq $NUMWORDS`
do
rnum=$((`${RANDOM_CMD}`%$tL+1))
sed -n "$rnum p" $WORDFILE | tr '\n' ' '
done
printf "\n"
rm /tmp/pick.a.random.word.or.phrase
我主要问:
#!/usr/bin/bash
# Collects all of the args, make sure to seperate with ','
IN="$*"
# Takes everything before a ',' and places them in an array
words=($(echo $IN | sed 's/,/ /g'))
# Get random indexi in range: 0, length of array: words
index=$(shuf -i 0-"${#words[@]}" -n 1)
# Print the random index
echo ${words[$index]}
如果不想使用shuff,也可以使用$RANDOM
:
#!/usr/bin/bash
# Collects all of the args, make sure to seperate with ','
IN="$*"
# Takes everything before a ',' and places them in an array
words=($(echo $IN | sed 's/,/ /g'))
# Print the random index
echo ${words[$RANDOM % ${#words[@]}]}
您可以使用来缩短脚本并删除临时文件
#!/usr/bin/bash
# Collects all of the args, make sure to seperate with ','
IN="$*"
# Takes everything before a ',' and places them in an array
words=($(echo $IN | sed 's/,/ /g'))
# Get random indexi in range: 0, length of array: words
index=$(shuf -i 0-"${#words[@]}" -n 1)
# Print the random index
echo ${words[$index]}
如果不想使用shuff,也可以使用$RANDOM
:
#!/usr/bin/bash
# Collects all of the args, make sure to seperate with ','
IN="$*"
# Takes everything before a ',' and places them in an array
words=($(echo $IN | sed 's/,/ /g'))
# Print the random index
echo ${words[$RANDOM % ${#words[@]}]}
在我看来,命令行参数处理很奇怪。为什么不直接使用普通的命令行参数呢?这使得问题变得微不足道:
#!/usr/bin/bash
shuf -en1 "$@"
当然,您可以只使用shuf-en1
,这仅仅是九次击键:
$ shuf -en1 word another_word "random phrase"
another_word
$ shuf -en1 word another_word "random phrase"
word
$ shuf -en1 word another_word "random phrase"
another_word
$ shuf -en1 word another_word "random phrase"
random phrase
shuf
命令行标志:
-e Shuffle command line arguments instead of lines in a file/stdin
-n1 Produce only the first random line (or argument in this case)
如果您确实坚持将参数一起运行,然后用逗号分隔,那么可以使用以下方法。与您的原始版本一样,如果参数中的某个单词可以进行glob扩展,那么它将表现出意外的行为,因此我真的不推荐它:
#!/usr/bin/bash
IFS=, read -ra args <<<"$*"
echo $(shuf -en1 "${args[@]}")
#/usr/bin/bash
在我看来,IFS=,read-ra args命令行参数处理非常奇怪。为什么不直接使用普通的命令行参数呢?这使得问题变得微不足道:
#!/usr/bin/bash
shuf -en1 "$@"
当然,您可以只使用shuf-en1
,这仅仅是九次击键:
$ shuf -en1 word another_word "random phrase"
another_word
$ shuf -en1 word another_word "random phrase"
word
$ shuf -en1 word another_word "random phrase"
another_word
$ shuf -en1 word another_word "random phrase"
random phrase
shuf
命令行标志:
-e Shuffle command line arguments instead of lines in a file/stdin
-n1 Produce only the first random line (or argument in this case)
如果您确实坚持将参数一起运行,然后用逗号分隔,那么可以使用以下方法。与您的原始版本一样,如果参数中的某个单词可以进行glob扩展,那么它将表现出意外的行为,因此我真的不推荐它:
#!/usr/bin/bash
IFS=, read -ra args <<<"$*"
echo $(shuf -en1 "${args[@]}")
#/usr/bin/bash
如果coreutils中的IFS=,read-ra args正好做到这一点,但是使用多个命令参数而不是单个逗号分隔的参数
shuf -n1 -e arg1 arg2 ...
-n1
选项表示只选择一个元素。-e
选项表示元素将作为参数传递(而不是通过标准输入)
然后,脚本只需在$*
中用空格替换逗号即可。我们可以使用bash参数替换来实现这一点:
#!/usr/bin/bash
shuf -n1 -e ${*//,/ }
这不适用于带有嵌入空格的元素。在coreutils中正好可以做到这一点,但是使用多个命令参数而不是单个逗号分隔的参数
shuf -n1 -e arg1 arg2 ...
-n1
选项表示只选择一个元素。-e
选项表示元素将作为参数传递(而不是通过标准输入)
然后,脚本只需在$*
中用空格替换逗号即可。我们可以使用bash参数替换来实现这一点:
#!/usr/bin/bash
shuf -n1 -e ${*//,/ }
这对带有嵌入空格的元素不起作用。这不是很简单,只要在1和$#
之间随机生成一个数字,然后简单地回显相应的参数就可以了吗?这取决于你拥有什么;你对“收集论据”的评论;请确保“用逗号分隔”不清楚,因为赋值不使用逗号,并且您没有显示如何调用命令
我只是抄袭了问题中的随机数生成:它在我的Mac上正常工作,在连续运行时生成值42405691和1817261076
n=$(( $(od -vAn -N4 -tu4 /dev/urandom) % $# + 1 ))
eval echo "\${$n}"
如果你真的下定决心,你甚至可以把它简化为一行:
eval echo "\${$(( $(od -vAn -N4 -tu4 /dev/urandom) % $# + 1 ))}"
使用eval
是安全的,因为它不涉及用户输入。如果$#
为0,脚本应检查是否至少提供了一个参数以防止被零除的错误。与以某种方式洗牌数据的解决方案相比,该代码的数据移动绝对最少
如果它打包在脚本随机选择中
,那么我可以运行:
$ bash random_selection Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
Feb
$ bash random_selection Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
Oct
$ bash random_selection Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
Nov
$
如果参数的总数足够大,以至于耗尽了参数空间,则需要重新考虑,但现有代码中存在该限制
选择稍微偏向于列表中较早的条目;您必须更好地拒绝非常接近范围内最大值的随机数。对于一个随机的32位无符号值,如果它大于$#*(0xFFFFFF/$#*)
,您应该生成另一个随机数。这不是简单地在1和$#
之间随机生成一个数字,然后简单地回显相应的参数吗?这取决于你拥有什么;你对“收集论据”的评论;请确保“用逗号分隔”不清楚,因为赋值不使用逗号,并且您没有显示如何调用命令
我只是抄袭了问题中的随机数生成:它在我的Mac上正常工作,在连续运行时生成值42405691和1817261076
n=$(( $(od -vAn -N4 -tu4 /dev/urandom) % $# + 1 ))
eval echo "\${$n}"
如果你真的下定决心,你甚至可以把它简化为一行:
eval echo "\${$(( $(od -vAn -N4 -tu4 /dev/urandom) % $# + 1 ))}"
使用eval
是安全的,因为它不涉及用户输入。如果$#
为0,脚本应检查是否至少提供了一个参数以防止被零除的错误。与以某种方式洗牌数据的解决方案相比,该代码的数据移动绝对最少
如果它打包在脚本随机选择中
,那么我可以运行:
$ bash random_selection Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
Feb
$ bash random_selection Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
Oct
$ bash random_selection Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
Nov
$
如果参数的总数足够大,以至于耗尽了参数空间,则需要重新考虑,但现有代码中存在该限制
选择稍微偏向于列表中较早的条目;您必须更好地拒绝非常接近范围内最大值的随机数。对于随机32位无符号值,如果它大于$#*(0xFFFFFFFF/$#*)
,则应生成另一个随机数。${words}始终为1。它应该是${#words[@]}@frangio:${#words}
并不总是1。它是$words
的字符长度;如果words
是一个数组,