使用shell反转三角形

时间:2015-02-19 19:01:44

标签: bash shell unix reverse

好的,所以我已经在这里工作了几天,我刚接触到这个整个bash UNIX系统的新东西,但我正在尝试编写一个脚本,用户输入一个整数,脚本将采用整数和使用作为基数输入的整数打印出三角形并减小直到达到零。一个例子是:

reverse_triangle.bash 4
****
***
** 
*

所以这就是我到目前为止所做的事情但是当我跑步时没有任何反应我不知道出了什么问题

#!/bin/bash
input=$1
count=1
for (( i=$input; i>=$count;i-- ))
       do 
           for (( j=1; j>=i; j++ ))
              do 
                   echo -n "*"
            done
       echo 
       done
exit 0

当我尝试运行它没有任何反应它只是进入下一行。非常感谢帮助:)

2 个答案:

答案 0 :(得分:2)

正如我在评论中所说,你的测试是错误的:你需要

for (( j=1; j<=i; j++ ))

而不是

for (( j=1; j>=i; j++ ))

否则,此循环仅在i=1时执行,并且变为无限循环。


现在,如果你想以另一种方式解决这个问题,那就更好了:

#!/bin/bash

[[ $1 = +([[:digit:]]) ]] || { printf >&2 'Argument must be a number\n'; exit 1; }
number=$((10#$1))
for ((;number>=1;--number)); do
    printf -v spn '%*s' "$number"
    printf '%s\n' "${spn// /*}"
done

为什么更好?首先,我们检查参数是否真的是一个数字。如果没有这个,您的代码将受到任意代码注入。此外,我们确保使用10#$1在基数10中理解该数字。否则,像09这样的参数会引发错误。

我们并不需要为循环提供额外的变量,所提供的参数足够好。现在的诀窍是:打印 n 次模式,一个很酷的方法是将 n 空间存储在printf的变量中:%*s将展开到 n 空格,其中 n printf找到的相应参数。
例如:

printf '%s%*s%s\n' hello 42 world

会打印:

hello                                     world

(有42个空格)。

编者注:%*s一般不会扩展到 n 空格,如上面的输出所示,其中包含 37 空格。
相反,*映射到42的参数是s字段的字段宽度,它映射到跟随参数world,导致字符串world 左空格填充为42 ;由于world的字符数为5,因此 37 空格用于填充 要使示例按预期工作,请使用printf '%s%*s%s\n' hello 42 '' world - 注意42后面的空字符串参数,确保整个字段由填充组成,即,空格(如果没有参数跟在42之后,你会得到同样的效果。)

使用printf&#39; -v选项,我们可以将printf格式化的任何字符串存储到变量中;在这里,我们在$number中存储spn个空格。最后,我们使用扩展*替换所有空格${spn// /*}


又一种可能性:

#!/bin/bash

[[ $1 = +([[:digit:]]) ]] || { printf >&2 'Argument must be a number\n'; exit 1; }
printf -v s '%*s' $((10#1))
s=${s// /*}
while [[ $s ]]; do
    printf '%s\n' "$s"
    s=${s%?}
done

这次我们使用前面的技术构造包含一堆s(用户给出的数字)的变量*。然后我们有一个while循环,循环而s非空。在每次迭代时,我们会打印s的内容,然后移除包含${s%?}的扩展s的字符,删除{{1}}的最后一个字符。

答案 1 :(得分:0)

gniourf_gniourf's helpful answer

为基础

以下更简单,表现更好:

#!/bin/bash

count=$1  # (... number-validation code omitted for brevity)

# Create the 1st line, composed of $count '*' chars, and store in var. $line.
printf -v line '%.s*' $(seq $count)

# Count from $count down to 1.
while (( count-- )); do
  # Print a *substring* of the 1st line based on the current value of $count.
  printf "%.${count}s\n" "$line"
done
  • printf -v line '*%.s' $(seq $count)是一个打印* $count次的技巧,感谢%.s*为每个提供的参数生成*,无论参数如何&#39 ;值(感谢%.s,它有效地忽略了它的参数)。 $(seq $count)扩展为$count个参数,从而生成由$count *个字符组成的字符串。总体而言,感谢-v line,它存储在变量$line
  • printf "%.${count}s\n" "$line"打印$line开头的$count字符的子字符串。长。