スペースを理解する

スペースを理解する

以下は、Ishmael SmyrnowがmacOSアイコンキャッシュを消去するために作成した1行のbashスクリプトです。

sudo rm -rfv /Library/Caches/com.apple.iconservices.store; sudo find /private/var/folders/ \( -name com.apple.dock.iconcache -or -name com.apple.iconservices \) -exec rm -rfv {} \; ; sleep 3;sudo touch /Applications/* ; killall Dock; killall Finder

源泉

複数行バージョンに戻す方法を学びたいと思います。これが私が今持っているものです:

sudo rm -rfv /Library/Caches/com.apple.iconservices.store
sudo find /private/var/folders/ -name com.apple.dock.iconcache -exec rm -rfv {} \;
sudo find /private/var/folders/ -name com.apple.iconservices -exec rm -rfv {} \;
sleep 3
sudo touch /Applications/*
killall Dock
killall Finder

Ishmaelのバージョンでは、セミコロンが改行と文字通りの\;セミコロンに使用されることを知っています。しかし、2つのセミコロンの間とアスタリスクの後にスペースを入れるのはどんな役に立ちますか?削除しても安全ですか?

 -exec rm -rfv {} \; ;
/Applications/* ;

ベストアンサー1

シェル言語の構文でスペースを使用するときは、マイナーな問題ではありません。

さまざまな種類のスペースを知ることも重要です。

  • スペースとタブは、構文内のトークンを区切るために使用されます。

  • 改行はトークンを分離しますが、コマンドも分離します。たとえば、

    array=(
      foo bar
      baz
    )
    

    (zshの構文は複数の異なるシェルでサポートされています)またはksh(Cで):

    (( 1
    + 2
    ))
    

    またはPOSIX sh(kshでも来ることができます):

    var=$((
      a + 
      b
    ))
    

    上記のスペース、タブ、または改行は要素を区別できます。

    しかし:

    cmd a
    cmd b
    

    2つの別々のコマンドを実行します。

    スペースの代わりに改行文字を使用できる場所は必ずしも明確ではなく、シェルによって異なる場合があります。

  • 一部のシェル(bashを含む)では、他のいくつかの文字が次のように分類されます。スペースロケールでは、構文のトークン区切り文字として使用でき、改行しないスペースを含むU + 00A0などの文字を含めることができます(次に分類されるロケールでのみ)。スペース)の場合はバイトでエンコードされますbash

その後、参照演算子("..."、、、、、、)があり、これはシェル構文から文字が持つ特別な意味を削除するために使用できます。'...'$'...'$"..."\

また、単独で使用したり、他の文字と組み合わせて文法で単語を区切る表示を形成することができるいくつかの特殊文字(ほとんど();<>&|ある程度`$)もあるので、周囲にスペースを追加する必要はありません。

たとえば、ksh では次のように書くことができます。

[[(a == b||d>c)&&0<1 ]]&&(echo yes)|cat

変える:

[[ ( a == b || d > c ) && 0 < 1 ]] && ( echo yes ) | cat

なぜなら||、、、、、...は分離できる単一のトークンであるからです(&&<&&

Bash(最小5.1)では、次のものが必要です。

[[(a == b||d>c)&&0 <1 ]]&&(echo yes)|cat

そうでなければ、ある種のエラーが発生したようです。

$ bash -c '[[(a == b||d>c)&&0<1 ]]&&(echo yes)|cat'
bash: -c: line 1: unexpected token 284 in conditional command
bash: -c: line 1: syntax error near `&0<'
bash: -c: line 1: `[[(a == b||d>c)&&0<1 ]]&&(echo yes)|cat'

(おそらくOutside of [[...]]、in cmd 0<file0<in自体が演算子なので、別のトークンとして扱われる可能性が高いからです。)

存在する:

foo \;;bar

あいまいさはありません。単語foo、区切り文字で処理されるスペース、引用符;\;ここと同じ)、トークン、およびthen。したがって、次のように処理されます。';'";";bar

foo ';' ; bar

スペースを追加しても害はなく、読みやすさを向上させるのに役立ちます。

このコードは、次のように作成(および改善)することもできます。

sudo zsh -c '
  rm -rfv /Library/Caches/com.apple.iconservices.store
  find /private/var/folders/ \
    "("
       -name com.apple.dock.iconcache -o \
       -name com.apple.iconservices \
    ")" -prune -exec rm -rfv {} +
  sleep 3
  touch /Applications/*'
killall Dock
killall Finder

あなたが気づくでしょう:

  • sudo一度だけ実行し、複数行で囲まれた引用符付き文字列を別々のzsh呼び出しの引数として渡すと、すべての文字がシェルの特別な意味を失います。
  • \改行の後に来るのは、上記に記載されていない別の特別なケースです。これにより、改行文字が消えます(内部シェルの場合、外部シェルの場合、バックスラッシュと改行文字は一重引用符内にあるため、リテラルのままです)。
  • 私たちは一人だけ電話します。find
  • 実行されるコマンドを構成する引数のリストを分離しないよう+にするために(シェルではなく)使用するため、各ディレクトリに対して1回ではなく、削除するすべてのディレクトリに対して1回呼び出されます。;find-execrm
  • -prunesoを使用すると、削除するディレクトリfindに入ろうとしません。rm
  • 私はより明確だと思うので、"("代わりに使用しています。\(普通はここを使用しますが'('、すべてが中において'...'使用できません。
  • globが一致しないときに文字通り渡されるバグ機能があるため、zsh -c代わりに使用します。したがって、隠しファイルがない場合は、inという名前のファイルが生成されます。 zshでは、一致するものがない場合はエラーが発生します。sh -cshshtouch /Applications/**/Applications

おすすめ記事