2

我遇到了这个漂亮的 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 "$@"
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

我哪里错了?

4

3 回答 3

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 "$@"
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 sleep 处理分数,但许多其他操作系统不处理。

于 2013-02-19T00:50:59.253 回答
1

这条线

echo "$1"| read -a to_sort

to_sort在管道完成后不再存在的子shell中设置值。要设置 的值to_sort并在以后使用它,您需要read在当前 shell 中执行该命令。一种可能:

read -a to_sort <<< "$1"
于 2013-02-18T22:56:09.337 回答
1

我看到 @that other guy 已经回答了,但我还是发布了这个......
这是我个人的做事方式。
编辑:粘贴代码时忘记了一些行

#!/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=("$@")
#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 "$@"; 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脚本文件而感到内疚:)

于 2013-02-19T01:05:29.730 回答