2013-02-18 61 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