シェルスクリプトの落とし穴

グラフィックスが広く使用されているにもかかわらず、シェルは今日までその関連性を失っていません。 また、グラフィカル環境よりもはるかに高速かつ簡単に操作を実行できる場合もあります。 しかし、ほとんどが気づいていないことがたくさんあります。

特定のシェルにアタッチしたくはありませんが、以下で考慮される可能性のすべてがPOSIX互換であるとは限りませんが、ksh / bash / zshで動作することが保証されます。



1.変数とテスト


シェルで文字列、数値、さらには変数を比較できることは秘密ではありません。 (:

[[ 2 -eq 3 ]] [[ "test" == "test" ]] [[ $VAR -eq 3 ]]
      
      





しかし、最後のオプションは、ランダムなタイプミス(VARの前に$を忘れていた)の後、この場合の動作をより詳細に研究させました。 驚いたことに、設計はエラーなく機能し、VAR値は$を忘れていないかのように置き換えられました。 さらに、VARで別の変数を参照する場合、すべて正常に機能します。

開発者は、再帰から自分自身を守ることを忘れていませんでした:

 $ V=V ; [[ V -eq 12 ]] -bash: [[: V: expression recursion level exceeded (error token is "V")
      
      





結局のところ、これはイースターエッグではなく、すべてが計画通りです。 詳細はman bashで説明されています。
[[and]]の間の言葉 チルダ展開、パラメータおよび変数

展開、算術展開、コマンド置換、プロセス置換、および引用削除が実行されます。

...

算術展開

...

評価は、算術評価で以下にリストされているルールに従って実行されます。

...

算術評価

...

式内では、パラメータ拡張構文を使用せずにシェル変数を名前で参照することもできます。


2.サードパーティのユーティリティなしでサブシェルから変数を取得します


シンプルなデザインがあるとしましょう:

 do_something | while read LINE ; do export VAR_N=${LINE##%*} ; done
      
      



初心者はしばしば、構築が完了した後にVAR_Nが利用できない理由について困惑する必要があります。 実際のところ、whileループでは、変数が親に到達しないサブシェルが作成されます。 サイクルから必要な変数を取得するには、たくさん汗をかかなければなりません。 原則として、インターネットで提供されるすべてのオプションは、出力を変数に保存し、解析を繰り返すことになります。

 VAR=$(cycle) VAR_N=$(echo "$VAR"|sed 'magic_sed')
      
      



それは動作しますが、どういうわけかいです。 はい、すべての種類のSED、Perl、およびその他の人生の喜びを繰り返し呼び出す必要があります。これは明らかにパフォーマンスに影響しません。 そして、もしあなたがそれらなしでできるなら、なぜそれらはすべてですか?

美しいセパレータで出力を正しく形成する必要があります。 たとえば、次のように:

 OLD__IFS="$IFS" IFS='~' #    set -- $(cycle) VAR_N="$1" VAR_NN="$2" IFS="$OLD__IFS"
      
      



そして、それははるかに明確であり、それを修正するのがはるかに簡単であれば、毎回通常のアイテムを作り直すよりも簡単です。



3.パイプからデータの一部を非表示にします


パイプの1つからデータの一部を非表示にして、ストリーム全体に接続し直す必要がある場合に、状況が発生することがあります。 この状況では、隠しデータをstderrにリダイレクトしてから、stderrからstdinに戻すことができます。

 $ ( { echo DATA ; echo HIDDEN_DATA >&2 ; } | sed 's/^/MODIFIED_/' ) 2>&1 | sed s/$/_CATCHED/ HIDDEN_DATA_CATCHED MODIFIED_DATA_CATCHED
      
      





4.チームの履歴を解析したい


lsの出力を解析するのが好きな人と一緒に、コマンドの履歴を解析するのも好きです(結果をさらに自動処理するため)。しかし、履歴以外は何も知りません。さらに、履歴の出力がカスタムチューニングされていることを考慮していません。 ここで、バックフィルに関する質問をすることができます:「履歴は他に何を見ることができますか?」(ネタバレのために特別に答えを隠します)(:

チームの履歴を解析したい場合は、お願いします
fcを使用します(help fcの詳細、任意のシェルに組み込まれています)。


5. if .. then .. else .. fi



.. && .. || ..



と異なることを覚えてif .. then .. else .. fi



.. && .. || ..





一部のリファクタリング愛好家は、コードをできるだけコンパクトにすることに熱心です。 上記の構造とその後のデバッグの交換を観察するのは特に面白いです。

これらの2つのデザインは単に異なるだけでなく、完全に異なっていますが、外見上は1つのことをしているように見えるかもしれません。

 if $(condition); then com_1; else com_2; fi condition && com_1 || com_2
      
      



明らかな違いは、最初のケースでは、com_2は1つのケースでのみ実行されるということです:conditionはfalseを返します。

2番目のケースでは、条件がfalseを返し、com_1がエラーを返す場合、com_2が起動されます。 信じられない? 自分で見てください:

  $ if true ; then false ; else echo 'hello' ; fi $ true && false || echo 'hello' hello
      
      





まあ、おそらくそれだけです。 最愛のsedについて少し言葉を述べたかったのですが、それはすでに何とか長い間起きていました。 おそらく別の時間(:



All Articles