スクリプト内の文字列のシェル独立エスケープ

スクリプト内の文字列のシェル独立エスケープ

私はこれのために(再び)困難を経験しています。

# only in bash
NORM=$'\033[0m'
NORM=$'\e[0m'

# only in dash
NORM='\033[0m'

# only in bash and busybox
NORM=$(echo -en '\033[0m')

echo目的は、出力の使用だけでなく、CLIツールなどのパイプ用の文字列に特殊文字を含めることです。

上記の特定のユースケースでは、を使用するのが$(tput ...)おそらく最善のアプローチです。ただし、外部ツールの要件は最小限に抑えられ、互換性は最大化する一般的なエスケープソリューションが必要です。

通常[ -z "$BASH_VERSION" ]「but」のような条件文を使って助けます。

  1. ビジボックスを検出する簡単な方法が見つかりませんでした。
  2. 5行目の一般変数の割り当て(if / else / fiを使用)はやや過度に見えます。
  3. 私は簡単な解決策を好む

答え1

あなたが望むものです"$(printf ...)"。スティーブンは素晴らしい暴露を書いた。printfそしてecho、単純な答えというよりは記事に近いのでここでは全体の内容を繰り返さないでしょう。懸案に関連する基調講演は次のとおりです。

  1. ~によるとPOSIX機能そして携帯性はとても良いです
  2. これは通常シェル組み込みであり、この場合は外部呼び出しや依存関係はありません。

echoまた、慣れて複雑になるとecho思ったので、切り替えに長い時間(例、ほんの数週間)かかったと付け加えるでしょう。printf(このすべてのフラグは何についてのものですか?)実際には非常に単純で、%最後に改行文字を含む固定テキスト以外のprintf操作にはもう気にしません。echo


Printfが簡単になりました

多くのオプションがありますprintf。特定の小数点以下の桁まで数字を印刷できます。それぞれ指定された固定幅(または最小または最大幅)を持つ複数のフィールドを印刷できます。文字シーケンスを含むシェル文字列変数を作成する\tか、\nこれらの文字シーケンスを印刷用のタブと改行として解釈できます。

これらすべてを行うことができ、必要なときに閲覧できるように可能であることを知る必要がありますが、ほとんどの場合、知っておくべきことは次のとおりです。

printf最初の引数として「format」という文字列を使用します。フォーマット文字列は、追加のパラメータを処理する方法(フォーマット方法など)を指定できます。他のパラメータ(形式パラメータ*でまったく引用されていない場合)は次のとおりです。無視される

英数字(およびその他の文字)を型パラメータに含めることで、そのまま印刷できます。バラよりlikeはprintf同じことをしますecho -nが、未知の理由で最初の引数を除くすべての引数を無視します。しかし、実際にはそうではありません。

たとえば、printf some test textこの例では、trysomeは実際には次のように処理されます。滞在printfそして、これには特別な内容が含まれておらず、残りの引数で何をすべきかを知らせないので、その引数は無視され印刷されるのはすべてですsome

%printf後続のパラメータに含まれるデータ型を指定するには、フォーマット文字列(の最初のパラメータ)と特定の文字が必要です。%s「文字列」を意味し、最もよく使用されます。

\nまたは、\tそれぞれの形式に応じて改行とタブに変換します。

これが実際に効率的に使用するために必要なすべてですprintf。非常に簡単ないくつかの例については、次のコードブロックを参照してください。

$ var1="First"
$ var2="Second"
$ var3="Third"
$ printf "$var1" "$var2" "$var3"       # WRONG
First$                                 # Only the first arg is printed, without a trailing newline
$
$ printf '%s\n' "$var1"                # %s means that the next arg will be formatted as a literal string with any special characters printed exactly as-is.
First
$
$ printf '%s' "$var1" "$var2" "$var3"  # When more args are included than the format calls for, the format string is reused.  This example is equivalent to using '%s%s%s' as the format.
FirstSecondThird$                      # All three args were printed; no trailing newline.
$
$ printf '%s\t%s\t%s\n' "$var1" "$var2" "$var3"
First   Second  Third                  # Tab separation with trailing newline.  This format is very explicit about what to do with three arguments.  Now see what happens if four are used:
$ var4="Fourth"
$ printf '%s\t%s\t%s\n' "$var1" "$var2" "$var3" "$var4"
First   Second  Third             # The specified format is reused after the three expected args,
Fourth                            # so this line has two trailing tabs.
$
$ printf '%s\n' "$var1" "$var2" "$var3"  # This format reuse can be used to advantage in printing a list, for example.
First
Second
Third
$
$ printf '%s\t' "$var1" "$var2" "$var3" ; printf '\n'  # Here is a dual command that could have args added without changing the format string...
First   Second  Third   
$ printf '%s\t' "$var1" "$var2" "$var3" "$var4" ; printf '\n'
First   Second  Third   Fourth              # ...as you can see here.
$                                           # It does print a trailing tab before the newline, however.

*もちろん、単一の引数書式指定子シーケンス(たとえば)を含む場合、書式文字列全体%sは、指定されたすべての引数を処理するために必要なだけ再利用されます。例をご覧ください。

答え2

printf任意の8進数などを印刷するのに適していますが、入力だけをしたいときESC- それでは、ただ入力してください。食生活の脱出が心配な場合は、CTRL+V最初。

だから...

NORM='^[[0m'

...上記の順序を入力した後、画面に表示される内容を表示できます。 ttyは印刷できない文字の出力をこのように引用しますが、シェルはテキストを読み取ります。ESC文字^[エスケープシーケンスの位置です。

この機能は設定可能ですが、ターミナルエミュレータプログラム、シェル、または他のものとは無関係です。システムカーネルは、sttyユーティリティ構成に基づいて入力を管理します。デフォルト設定 - BSD、Linux、または(私の知る限り)ほとんどすべてのUNIXシリーズシステム - 通常、次のほとんどが含まれます。

stty --help 2>&1 | sed -e '/Special/,$!d;/./!q'

Special characters:
 * discard CHAR  CHAR will toggle discarding of output
   eof CHAR      CHAR will send an end of file (terminate the input)
   eol CHAR      CHAR will end the line
 * eol2 CHAR     alternate CHAR for ending the line
   erase CHAR    CHAR will erase the last character typed
   intr CHAR     CHAR will send an interrupt signal
   kill CHAR     CHAR will erase the current line
 * lnext CHAR    CHAR will enter the next character quoted
   quit CHAR     CHAR will send a quit signal
 * rprnt CHAR    CHAR will redraw the current line
   start CHAR    CHAR will restart the output after stopping it
   stop CHAR     CHAR will stop the output
   susp CHAR     CHAR will send a terminal stop signal
 * swtch CHAR    CHAR will switch to a different shell layer
 * werase CHAR   CHAR will erase the last word typed

これNext文字は通常構成される文字です。CTRL+V。それは役に立つかもしれません - あなたはできますCTRL+VそれからCTRL+Jたとえば、改行文字は、シェルが読み取る機会がある前に入力バッファに挿入されます。一度試してください$PS2。それ以外の場合は、表示できるシェルのプロンプトが表示されないことがわかります。拉致された貝の場合TABキーを使用している場合は、通常、コマンドラインにプレフィックスを付けてキーをそのまま入力できます。CTRL+V。テキストを入力できます。CTRL+D EOF文字とテキストCTRL+C 整数数値(使用しない場合zsh同じ方法で。

しかし、これらの文字のほとんどはシェルに特別ではなく、文字通り入力するときに引用する必要さえありません。(もちろん改行も可能ですが)

stty -a端末がどのように構成されているかを明確に把握してください。おそらく私の端末と他のすべての端末とほぼ同じように構成されているでしょう。

実際に入力するとESCシェルスクリプトを編集すると、ファイルにそのまま残ります。リテラル文字は、スクリプトが呼び出されるたびに配置される場所であり、適切な意味を与えるために拡張や他の解釈は必要ありません。

関連情報