あなたがFacebookの「It's FOSS」をフォローしているなら、毎週のBashチャレンジに気づいているかもしれません。 LinuxスキルをテストするためにBashスクリプトを実行することは、Yes I Know ItとFOSSの共同作業です。
私たちはこのBash ChallengeをFacebookから、通常のWeb上のより幅広いユーザーにもたらしています。 これは、このシリーズの5回目の記事です。 最初の4つの課題は、Facebookのページにあります。 本の形でこれらの課題を購入することもできます。
バッシュチャレンジ5
私たちはあなたに端末のスクリーンショットを見せて、そして結果が我々が期待していたものではない理由を説明するようにあなたに頼みます。 もちろん、最も面白い、そして最も創造的な、チャレンジの一部は、正しい結果を得るために画面に表示されたコマンドを修正する方法を見つけることです。
プレイする準備はできましたか? それで、今週の挑戦はここにあります:
マイバッシュはどうやって数えるのかわからない[難易度1]

今週は、各行に1つずつ、整数を含むデータファイルがあります。
cat sample.data 102 071 210 153
そして、これらすべての数値の合計を計算したいと思います。
declare -i SUM=0 while read X ; do SUM+=$X done < sample.data echo "Sum is: $SUM"
残念ながら、私が得た結果は間違っています(予想される結果は536でした)。
Sum is: 522
チャレンジ
あなたの挑戦は、見つけることです:
- なぜその結果が間違っていたのでしょうか。
- 正しい結果を得るためにコマンドを修正する方法
★Bashの内部コマンドやシェルの代用のみを使用して解決策を見つけることができれば、おまけのユニコーンポイント。
以下のコメント欄であなたの解決策を読むのを楽しみにしています! 創造的であることを忘れないでください。
詳細が少ない
この課題を解決するために、私は使用しました:
- GNU Bash、バージョン4.4.5(x86_64-pc-linux-gnu)
- Debian 4.8.7-1(amd64)
- すべてのコマンドは、標準のDebianディストリビューションに同梱されているものです。
- コマンドはエイリアスされませんでした
溶液
再現方法
これが、この課題を解決するために使用した生のコードです。 これを端末で実行すると、チャレンジの図に表示されているのとまったく同じ結果を再現できます(私と同じソフトウェアバージョンを使用していると仮定します)。
rm -rf ItsFOSS mkdir -p ItsFOSS cd ItsFOSS cat > sample.data << 'EOT' 102 071 210 153 EOT clear cat sample.data declare -i SUM=0 while read X ; do SUM+=$X done < sample.data echo "Sum is: $SUM"
なにが問題だったの ?
問題は071
値によって引き起こされました。 お気づきのとおり、この番号は0
から始まります。おそらく、ここですべてのデータが3桁でフォーマットされていることを確認するためです。 Cプログラミング言語から継承された不幸な規則に従って、整数の前に0
付けることは、その数値が10 進数ではなく8進数で表されることを指定する方法です。
8進数は0
から7
までの数字で表されます。 これが簡単な変換表です。
オクタル | 10進数 |
---|---|
0 | 0 |
1 | 1 |
2 | 2 |
3 | 3 |
4 | 4 |
5 | 5 |
6 | 6 |
7 | 7 |
10年 | 8 |
11 | 9 |
12年 | 10年 |
13年 | 11 |
14年 | 12年 |
.. | .. |
71 | 57 |
この最後の値は、合計を評価するときにエラーを引き起こしたものです。 Bashは071
を読み、 57
10進数値を表す8進数として解釈しました。 簡単に確認できます。
echo $((071)) 57
それを修正するには?
この問題を解決するための2つの主な戦略があります。 先行ゼロを除去します。 あるいは、シェルに私のすべての数字を理解させる方法を見つけることは10進数値です。
先行ゼロの削除
これは、 sed
externalコマンドを使用して先行ゼロを削除する簡単な解決策です。
declare -i SUM=0 while read X ; do SUM+=$X done < <(sed -E s/^0+// sample.data) echo "Sum is: $SUM"
(ボーナス質問:なぜ私はプロセス置換の代わりにパイプを使わなかったのですか?)
基底を明示的に指定する
以前の解決策は(ほとんど)簡単です - しかしBashは私たちが物事をより良くすることを可能にします。 データを修正するのではなく、数値を8進数(8進数)ではなく10進数(10進数)で表すように明示的に指定します。 base#value
構文を使用してそれを行うことができます。
これら3つの例を比較してください。
echo $((071)) # The leading `0` specify the number as octal 57 echo $((8#071)) # We *explicitly* specify base 8 (octal) 57 echo $((10#071)) # We *explicitly* specify base 10 (decimal) 71
最初のコマンドを修正して正しい結果を得るためには、すべてのデータに基数10を明示的に指定するだけです。
declare -i SUM=0 while read X ; do SUM+=$((10#$X)) done < sample.data echo "Sum is: $SUM"
そして、これが正しい結果です。 あなたがその挑戦を楽しんだことを願っています。 もっと楽しんでください。
著者バイオ: 私はSylvain Leroux、情熱によるソフトウェアエンジニア、職業による教師です。 私はコンピュータサイエンス&情報技術をあらゆるレベルで教えることに15年の経験があります。 私はLinuxとOpenSourceの技術を強く支持しています。 私はYes I Know ITを設立し、オンラインコースと無料ビデオを通じて、その経験をより多くのユーザーと共有しています。 Twitterで私に連絡することを躊躇しないでください。