2013-02-18 5 views
2

Я натолкнулся на этот отличный скрипт bash, который немного укусил.Улучшение сортировки сна в bash

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

Он спит в течение секунд, заданных номером, затем выводит это число. Самые низкие числа сначала пробуждаются.

Я думал, что его можно улучшить, сначала разделив числа на максимальное число в списке, затем пропустив его и умножив на max при его выходе.

Вот моя первая попытка:

#!/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

... если вы пытаетесь сделать sleepsort более эффективным, я думаю, вам может потребоваться переосмыслить подход ... – nneonneo

+0

@nneonneo Я пытаюсь сделать это быстрее. Я знаю, что это потерянное дело, но я хочу сразиться, чтобы помочь мне узнать больше о bash. – Pureferret

ответ

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, которое вы уважали. –

+0

@that other guy: Я видел ваш ответ прямо до того, как я закончил свой ответ, но я работал с ним немного, поэтому я все равно его разместил :) Я видел, что вы понимаете использование переменной 'final_var', я этого не делал. – 244an

+0

Вау! Благодарю. Это много, чтобы уйти и переварить. Запустив его быстро, он, кажется, печатает только первое число. Я уйду и просмотрю код и выясню, работает ли моя оболочка сна GNU или нет. – Pureferret

1

Эта линия

echo "$1"| read -a to_sort 

устанавливает значение to_sort в подоболочки которая больше не существует после того, как трубопровод будет завершена. Чтобы установить значение to_sort и сможете использовать его позже, вам необходимо выполнить команду read для выполнения в текущей оболочке. Одна из возможностей:

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

Я видел, что @, что другой парень уже ответил, но я все равно его отправлю ...
Некоторые из них - это мой личный способ делать вещи.
EDIT: забыл несколько строк при вставке в коде

#!/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 

EDIT 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

+1

Я не понимаю точно, что вы хотите отсортировать, если вы хотите, чтобы все заданные числа (параметры) были отсортированы, вы можете сделать это вместо этого при настройке to_sorted: 'declare -a to_sort = ($ (tr '' '\ n '<<< "$ @" | sort)) '. Я также добавил комментарий относительно имени файла сценария. – 244an

+0

Привет, Идея Sleepsort заключается в том, что он сортирует число, спя. Это не эффективно или быстро, но я думал, что попытка улучшить это может помочь мне учиться. Поэтому предварительная сортировка (сортировка до того, как она «отсортирована» программой) не имеет смысла. – Pureferret

Смежные вопросы