2013-02-18 62 views
2

我遇到了这个漂亮的bash脚本,这是一个小小的borked。在bash中改进睡眠排序

#!/bin/bash 
function f() { 
    sleep "$1" 
    echo "$1" 
} 
while [ -n "$1" ] 
do 
    f "$1" & 
    shift 
done 
wait 

它休眠数字给出的秒数,然后输出该数字。最低的数字首先醒来。

我在想这可以通过首先将数字除以列表中的最大数字,然后运行它并在出现时乘以最大值来改进。

这是我第一次尝试:

#!/bin/bash 

declare -a to_sort 

function f() { 
    sleep "$1" 
    final_var=$(echo "$1*$2"|bc) 
    echo "$1" 
} 
function max(){ 
for var in "[email protected]" 
do 
    if [ "$var" -gt "$max" ] # Using the test condition 
    then 
     max="$var" 
    fi 
done 
} 

echo "$1"| read -a to_sort 

let max_var = max to_sort 

for i in "${to_sort[@]}" 
do 
    parsed_var=$(echo "$i/$max_var"|bc) 
    f parsed_var max_var & 
    shift 
done 
wait 

我要去哪里错了?

+2

...如果您想让sleeppsort更高效,我想您可能需要重新考虑这种方法... – nneonneo 2013-02-18 22:40:17

+0

@nneonneo我试图让它更快。我知道这是一个失败的原因,但我想争取帮助我了解有关bash的更多信息。 – Pureferret 2013-02-18 22:53:01

回答

6

有7个语法和逻辑问题阻止了它的工作,如下面的评论。

#!/bin/bash 

declare -a to_sort 

function f() { 
    sleep "$1" 
    final_var=$(echo "$1*$2"|bc) 
    #Output result after multiplication 
    #and skip decimals 
    echo "${final_var%.*}" 
} 
function max(){ 
# Initialize max so we have something to compare against 
max=$1 
for var in "[email protected]" 
do 
    if [ "$var" -gt "$max" ] 
    then 
     max="$var" 
    fi 
done 
# output the max we found 
echo $max 
} 

# Avoid assigning in subshells 
read -a to_sort <<< "$1" 
#This is how you assign the output of a command 
max_var=$(max "${to_sort[@]}") 

for i in "${to_sort[@]}" 
do 
    # Add scale to avoid truncating all to 0 
    parsed_var=$(echo "scale=6; $i/$max_var"|bc) 

    # expand variables 
    f $parsed_var $max_var & 
    shift 
done 
wait        

另请注意,GNU睡眠处理分数,但许多其他操作系统没有。

+1

+1:出色的工作。通过'$ parsed_var'和'$ i'(而不是'$ parsed_var'和'$ max_var')可能会更简单,这意味着您不需要在唤醒后进行乘法运算。但是,这是OP尊重您的设计决定。 – 2013-02-19 00:55:45

+0

@那个其他人:我在回答完之前看到了你的回答,但是我用了一些东西,所以我发布了它:)我看到你明白变量'final_var'的用法,我没有。 – 244an 2013-02-19 01:11:35

+0

哇!谢谢。这是很多消除和消化。快速运行它似乎只打印第一个数字。我将离开并查看代码并确定我的shell是否使用GNU睡眠。 – Pureferret 2013-02-20 09:17:26

1

此行

echo "$1"| read -a to_sort 

设置的to_sort在流水线完成后不再存在一个子shell的值。要设置值to_sort并稍后能够使用它,需要在当前shell中执行read命令。一种可能性:

read -a to_sort <<< "$1" 
1

我看到@那个其他人已经回答了,但我反正这个......
一些在这是我个人的做事方式。
编辑:代码粘贴时忘了一些线条

#!/usr/bin/env bash 

# I have learned that the above is prefered over "#!/bin/bash", 
# to be more portable I think. 


# Do this here (instead of 'echo "$1"| read -a to_sort' below (which was 
# wrong anyway) because you chose to use "for i in 'to_sort'" below 
# you can't use 'shift' there so you must use all arguments already here. 
declare -a to_sort=("[email protected]") 
#debug: declare -p to_sort 

function f() { 
    sleep "$1" 

    # This can be done in another way, see below 
    # (and "final_var" is not used anywhere else) 
    #final_var=$(echo "$1*$2"|bc) 
    final_var=$(bc <<< "$1 * $2") 
    #debug: echo "\$1:$1; \$2:$2; final_var:$final_var" 

    echo "$1" 
} 

function max() { 
    res=0 
    for var in "[email protected]"; do 
    # Tip: use ((...)) when testing numeric values, no need for "$" when 
    # using that. 
    #if [ "$var" -gt "$max" ] # Using the test condition 
    if ((var > max)); then 
     # You can't set a return value for the function, echo at the en instead 
     #max="$var" 
     res="$var" 
    fi 
    done 
    echo "$res" 
} 

# This is wrong (as @chepner points out) 
#echo "$1"| read -a to_sort 
# if used here it should be 'to_sort[0]="$1"', when using like this 
# there is no need to use "declare -a ..." 

# This is wrong 
#let max_var = max to_sort 
# - no space before or after "=" 
# - not necessary to us "let" 
# - can't assign directly from a function 
# Should be 
max_var=$(max "${to_sort[@]}") 
#debug: echo "max_var:$max_var" 

for i in "${to_sort[@]}"; do 
    # This is wrong 
    #parsed_var=$(echo "$i/$max_var"|bc) 
    # - as far as I know bc needs "scale" when divide (* bad english?) 
    # otherwise it's truncated to integer. 
    # - nicer to use "command <<< text" than "echo text | command" 
    parsed_var=$(bc <<< "scale = 3; $i/$max_var") 

    # You must have "$" here 
    #f parsed_var max_var & 
    f "$parsed_var" "$max_var" & 

    # This is wrong here since you are not using the parameters 
    # of the script anymore. 
    #shift 
done 

wait 

我离开调试线,当我调试运行它,我得到这个:

-$ ./sleeping 1 2 3 
declare -a to_sort='([0]="1" [1]="2" [2]="3")' 
max_var:3 
final_var:.999; $1:.333; $2:3 
final_var:1.998; $1:.666; $2:3 
final_var:3.000; $1:1.000; $2:3 

编辑2: 我用调试输出更改了上一节中使用的名称。我偶然发现了这个:
http://www.talisman.org/~erlkonig/documents/commandname-extensions-considered-harmful
当在SO读这里的帖子(现在找不到它)。所以我不想因为脚本文件导致任何人使用.sh而犯内疚:)

+0

就像我与['那个人']说的(http://stackoverflow.com/questions/14946607/improving-sleep-sort-in-bash#comment21028819_14948015)很多反馈谢谢。这似乎在运行,但是当你有很多小数和大数混合在一起的时候,这并不是一种排序。我会走开想一想,尽管我怀疑它已经达到了某些数字的最低睡眠数量,并且它们最终在同时。 – Pureferret 2013-02-20 09:20:26

+1

我不明白你想要排序的内容,如果你想要对所有给定的数字(参数)进行排序,你可以在设置to_sorted时进行排序:'declare -a to_sort =($(tr'''\ n'<<<“$ @”| sort))'。我还添加了关于脚本文件名称的评论。 – 244an 2013-02-20 10:38:07

+0

嗨,sleeppsort背后的想法是,它通过睡觉来排序数字。这不是有效或快速,但我认为试图改善它可能会帮助我学习。因此,对它进行预先分类(在程序“分类”之前对其进行分类)没有任何意义。 – Pureferret 2013-02-20 13:06:42