🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

シェルスクリプト

シェルスクリプトは、UNIX系のOSもしくはコマンドラインインタプリタ向けに記述されたスクリプト。bash/zshといったシェルによって実行されるため、このように呼ばれています。バッチ処理などに使用されており、テキストファイルに書かれた命令を順に実行します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

最適化

最適化とはメソッドやデザインの最適な処理方法を選択することです。パフォーマンスの向上を目指す為に行われます。プログラミングにおける最適化は、アルゴリズムのスピードアップや、要求されるリソースを減らすことなどを指します。

Q&A

解決済

4回答

1080閲覧

【Bash】【シェル】コードを最適化したいです

KARI

総合スコア9

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

シェルスクリプト

シェルスクリプトは、UNIX系のOSもしくはコマンドラインインタプリタ向けに記述されたスクリプト。bash/zshといったシェルによって実行されるため、このように呼ばれています。バッチ処理などに使用されており、テキストファイルに書かれた命令を順に実行します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

最適化

最適化とはメソッドやデザインの最適な処理方法を選択することです。パフォーマンスの向上を目指す為に行われます。プログラミングにおける最適化は、アルゴリズムのスピードアップや、要求されるリソースを減らすことなどを指します。

0グッド

0クリップ

投稿2019/11/20 05:42

編集2019/11/20 05:45

##■質問内容
以下の問題に対してコードを作成し、テストは合格するのですが実行しようとしたところ「Execution Timed Out (12000 ms)」のメッセージが出てきました。
テストでは動くので恐らくコードを最適化する必要があるのではないかと思います。
このコードをどう書き換えればよいのか、また文法が間違っているところがあれば教えていただきたいです。

■問題のサイト

https://www.codewars.com/kata/growth-of-a-population/train/shell

■問題

とある町は"$1"人の住民が住んでいます。人口は毎年"$2"%増加し、さらに毎年"$3"人新しい住民が住みます。
町は住民を"$4"人以上にするために何年必要ですか?

At the end of the first year there will be:
1000 + 1000 * 0.02 + 50 => 1070 inhabitants

At the end of the 2nd year there will be:
1070 + 1070 * 0.02 + 50 => 1141 inhabitants (number of inhabitants is an integer)

At the end of the 3rd year there will be:
1141 + 1141 * 0.02 + 50 => 1213

It will need 3 entire years.

※パーセントパラメーターが2の場合、0.02に変換する必要があります

Bash

1#!/bin/bash 2nbYear() { 3 human=$1 4 year=0 5 inc=`echo "scale=5; $2/100" | bc` #パーセンテージに変換 6 while true 7 do 8 human=`echo " $human + $human * $inc + $3" | bc | sed s/.[0-9,]*$//g` #小数点以下を切り捨て 9 year=$(($year + 1)) 10 if [ "$(echo "$human >= $4" | bc)" -eq 1 ]; then 11 echo $year 12 break 13 fi 14 done 15} 16 17nbYear $1 $2 $3 $4

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

[[ $# -eq 5 ]] && echo $5 || echo 0

いろんな書き方がありますが、

三項演算子
https://code-examples.net/ja/q/3c53ed

[[ ]] については
https://qiita.com/Riliumph/items/f07272fa9b0834032a9d

[ ] はtestという外部コマンドで、[[ ]] はbash独自の記法(文法)です。

$total * $percent / 100

の場合、計算式中で少数化した場合の算術結果がどうなるか(どのタイミングで少数の切り捨てが起きているか)が記憶になかったので、確実そうな整数化を行いました。
とりあえずLLONGまでは扱えるからいいかな、と…。
普段はshellで少数をほとんど取り扱わないので。

投稿2019/11/21 02:15

KeisukeKoga

総合スコア125

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KeisukeKoga

2019/11/21 02:18

コメントのつもりが回答に書いてしまいました、すいません。
otn

2019/11/21 02:21

昔々の sh では [ や test は外部コマンドでしたが、今はシェル組み込みコマンドになっていると思います。 bash / dash / ksh / zsh
KARI

2019/11/21 04:14

教えていただきありがとうございます。 色んな書き方があるのが分かり大変勉強になりました。
guest

0

というかbc使っていいならbcに全部やらせれば1プロセスで済むのでそれでよいのではないかとは思うのですが。

bashの演算能力だけでやれということなら、

#!/bin/bash nbYear() { total=$1 percent=$2 inc=$3 limit=$4 year=$( [[ $# -eq 5 ]] && echo $5 || echo 0 ) percent_inc=$(( $total * 100 * $percent / 10000 )) total=$(( $total + $percent_inc + $inc )) year=$(( year + 1 )) echo "$year : total = $total ( percent = $percent_inc , inc = $inc )" if [[ $total -ge $limit ]] ; then echo "Over : $year on Humans is $total" else nbYear $total $percent $inc $limit $year fi } nbYear $1 $2 $3 $4

とかでしょうか。
bcを介さないので一切少数を考慮せず、shellは切り捨てなので、人数のように切り捨てでよいものは切り捨てのまま取り扱ってしまったほうが素直ですね。

エラー検知していないので、bashの数値上限でループ起こしてSegmentation起こして死ぬと思います。

実行結果:

# sh test.sh 1000 2 50 1200 1 : total = 1070 ( percent = 20 , inc = 50 ) 2 : total = 1141 ( percent = 21 , inc = 50 ) 3 : total = 1213 ( percent = 22 , inc = 50 ) Over : 3 on Humans is 1213

投稿2019/11/20 16:12

KeisukeKoga

総合スコア125

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KARI

2019/11/21 00:57 編集

ご回答ありがとうございます。 whileを使わずループする方法があるんですね。 year=$( [[ $# -eq 5 ]] && echo $5 || echo 0 )   →この部分の行われていることは分かるのですが、初めて見る文法なのでどう検索したらいいか分からないです。    この書き方をまとめているサイト等ありましたら教えていただけないでしょうか。 percent_inc=$(( $total * 100 * $percent / 10000 ))   →これは$(( $total * $percent / 100 ))では駄目なのでしょうか?
guest

0

ベストアンサー

そんなに遅いとは思えないのですが。
あと、ifの条件が意味不明です。これだとエラーになると思いますが。違うコードを張り付けた?

bcを使う必要もないので、bashの計算機能だけで行けます。

Bash

1#!/bin/bash 2nbYear() { 3 year=0 4 human=$1 5 inc=$2 6 come=$3 7 limit=$4 8 while true 9 do 10 let human+=human*inc/100+come 11 let year++ 12 if [ $human -ge $limit ]; then 13 echo $year 14 break 15 fi 16 done 17} 18 19nbYear $1 $2 $3 $4

引数が正当か(数字が4つ)をチェックしてないので、不正な引数だと無限ループですね。

投稿2019/11/20 15:24

otn

総合スコア85890

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KARI

2019/11/21 01:05

ご回答ありがとうございます。 if文は if [ $human -ge $4 ]; then と修正し忘れていました。 こんなに見やすいコードになるんですね。 1つ質問があるのですが、引数に少数が入力されるとなったらそれはbcを使うしかないのでしょうか?
otn

2019/11/21 01:21 編集

整数演算にはいろんな記法がありますが、Bashなら let がおすすめです。 小数を小数として計算したければ、bcですね。 倍精度浮動小数点の範囲で良ければawk/Perl/Python/Rubyも使えます。 あるいは、例えば 0.02 という入力を 2 ÷ 100 として整数演算に帰着することは文字列処理すれば十分可能です。
KARI

2019/11/21 01:34

ありがとうございました! これからは let を活用していきます。
guest

0

 #小数点以下を切り捨て

コメントの前に全角スペースが入っています。

あと、if...thenの条件判定は、

if [ $human -ge $4 ]; then

で良くないですか?

投稿2019/11/20 07:00

KojiDoi

総合スコア13692

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KARI

2019/11/20 07:16

ご回答ありがとうございます。 humanの小数点以下を切り捨てるコードを作る前のIF文が修正しないままになってました。 コメント部とIF文を修正して実行してもタイムアウトになってしまうのですが、もはやコードを根本から変えるしかないのでしょうか?
KojiDoi

2019/11/20 07:58

私がやってみた範囲では再現せずちゃんと結果が出ています。タイムアウトということですが、その間なんのメッセージも出力されていないのですか?
KARI

2019/11/20 08:02

Shell Stdout 15 Shell Stdout 10 Shell Stdout 94 Shell Stdout 151 Shell Stdout 116 Basic tests Shell Stdout 15 Shell Stdout 10 Shell Stdout 94 Shell Stdout 151 Shell Stdout 116 STDERR Execution Timed Out (12000 ms) とメッセージが出ています。
KojiDoi

2019/11/20 13:51

数字は$yearなんでしょうか。 Shell Stdout とかBasic testsは誰が出しているのでしょうか、質問の通りのスクリプトだとすればあり得ない出力です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問