私の言葉は、env
次の形式のGNUまたはBSDコマンドを使用していることです。env
env [name=value ...] [utility [args ...]]
特殊文字を部分的にエスケープする方法はないようですが、その部分を解析するvalue
方法がわかりません。env
value
env
シェルの機能を使ってこれを行う方法はいくつかありますが、シェルの助けを借りずにリテラル文字列を渡したいと思います(execute byと似ていますexec
)。つまり、コマンドでサポートされている改行文字を含むいくつかのenv
リテラル文字列形式を見つける必要があります。例えば:
env FOO=LITERAL_STRING ruby -e 'puts ENV["FOO"]'
これにはLITERAL_STRING
改行文字を含むリテラル文字列を含める必要があり、env
形式を理解する必要があります。
上記のコマンドを使用すると、予想される出力は次のようになります。
hello
world
可能かどうか知りたいです。ご協力ありがとうございます。
環境
env
BSDを使用しているため、
env
バージョンを印刷できません。これがman
役に立つかどうかはわかりません。$ man env | tail -n1 BSD April 17, 2008 BSD
オペレーティングシステム
$ sw_vers ProductName: macOS ProductVersion: 11.6 BuildVersion: 20G165
答え1
あなたの理解が間違っています。"hello\nworld"
変数に何かを保存すると、\n
文字通り解釈されます。printf
または、フラグecho
などのツールを呼び出す場合にのみ-e
コンソールに印刷するときに、これらのバックスラッシュシーケンスを展開します。
あなたの場合、変数を環境に渡して改行を拡張したい場合は、次を使用することをお勧めします。ANSI Cスタイル$'...'
参照演算子ksh93 バージョンは、bash や zsh を含むいくつかの異なるシェルでサポートされるようになりました。
env FOO=$'hello\nworld' ruby -e 'puts ENV["FOO"]'
あるいは、移植性が問題の場合、簡単な解決策は目的の場所に改行文字を配置することです。
f="hello
world"
env FOO="$f" ruby -e 'puts ENV["FOO"]'
答え2
牛に似た一種の栄養そしてFreeBSD env
-S
引数を空白に分割し、結果文字列に次のものを含むがこれらに限定されない多数のエスケープ文字を解釈する(「分割」)オプション[1]があります\n
。
$ env -S 'foo=bar\nquux printenv foo'
bar
quux
$ env -S 'foo=bar\nquux' printenv foo
bar
quux
[1]デフォルトの用途はshebangライン用ですが、コマンドラインが必要な他の場所でも使用できますが、ほとんどのvteベースの端末オプション#! ...
と同様に、これを解釈するためにシェルの代わりに一時パーサを使用します。-e
答え3
このenv
コマンドは、実行時にシステムコールから複数のパラメータを取得します(他のコマンドと同様)execve()
。これを実行するプロセスは、次のことを行います。
execve("/path/to/env", ["env", "-options", "var=value", "cmd", "arg"], environ);
順次実行されますenv
(通常、同じプロセス内で)。
execve("/path/to/cmd", ["cmd", "arg"], modified_environ);
どこmodified_environ
にあるががenviron
追加されているか、inで始まる文字列がvar=value
すでに1つ以上ある場合、その最初の文字列は(少なくとも)に置き換えられます。var=
environ
var=value
これらのパラメータはNULで終わるバイト配列なので、含めることができない唯一のバイトはNULバイトです。名前と値にNULバイトを含めることができない環境変数にも同じことが当てはまります。
env
起動時に、そのパラメータは最初から最後まで処理されます。
で始まるものは-
オプションと見なされます。
-
一人でも古代の形で-i
無視されますenviron
。
--
少なくとも1つを含む(またはオプションの終わりを表示するために使用できる)次のオプションは、=
環境変数文字列(上に配置されている)として扱われますmodified_environ
。文字を含まないオプションではない最初の引数は=
コマンド名として扱われます(最初の引数としてコマンドに渡され、クエリ内の実行可能ファイルへのパスとしても使用されます$PATH
)。
-
これ以降のすべての引数は、文字で始まったり文字を含めたりしても、コマンドの引数として渡されます=
。
したがって、文字だけがenv
それ自体で特別です。オプション処理中にのみ、コマンド名を見つける前にのみ可能です。-
=
-
=
-
で始まる環境変数名またはで始まるコマンド名を渡すには、-
次のようにします--
。
execve("/usr/bin/env", ["env", "--", "-var-=value", "cmd"], environ);
execve("/usr/bin/env", ["env", "--", "-cmd-"], environ);
複数env
の実装では-
、次のものは--
まだコマンド名とは見なされません。したがって、名前付きコマンドを呼び出す前に、-
1つ以上の環境変数を渡す必要があります。
execve("/usr/bin/env", ["env", "--", "dummy=", "-", "args"], environ);
(または代わりに、または/path/to/-
コマンドのパスルックアップを無視して使用してください)。./-
-
$PATH
-
env
=
ただし、名前に文字が含まれて=
渡されないコマンドは実行できませんmodified_environ
。=
この場合、この役割を回避する方法はありません。
しかし、あなたの場合、NULバイトを除いてenv
FOO=LITERAL_STRING
文字自体は問題ではありません。LITERAL_STRING
env
このコマンドを実行するために言語でコードを書くとき、env
その言語には文字通り入力できない文字がある可能性があります。
たとえば、perl
次のことができます。
exec "env", "--", "-text-=hello\nworld\n", "printenv", "--", "-text-";
改行文字を二重引用符で囲んで表現します\n
が、次のようにすることもできます。
exec qw(env --), q(-text-=hello
world
), qw(printenv -- -text-);
改行文字を含む文字列を渡します。
Bourneに似たシェル言語の構文では、改行文字は一重引用符または二重引用符(たとえば、q(...)
参照qq(...)
演算子perl
)の中にある場合は特別ではないため、次のようにすることができます。
exec env -- "-text-=hello
world
" printenv -- -text
"..."
参照演算子が使用されていないCシェルまたはrcシェルでは、状況が異なります。
あなたのenv FOO=LITERAL_STRING ruby -e 'puts ENV["FOO"]'
コードはシェル言語のコードのように見えます。ほとんどすべてのシェルがスペースを単語区切り文字と'...'
引用演算子として理解するため、この構文はほとんどのシェルに有効です。
exec
最初にこれを省略すると、シェルは子プロセスでコマンドを実行し、そのプロセスが終了または中断されるのを待ちます。
これが改行文字を文字通り(おそらくシェルではない)入力したり、何らかの形のエンコーディング(、、、...)を許可しないが、ほとんどのシェルのような引用演算子を明確にサポートするenv FOO=LITERAL_STRING ruby -e 'puts ENV["FOO"]'
言語であれば、BSDがすでにトリックを実行することをを除いて\n
%0a
'...'
env -S
@UncleBillyが提案しましたperl
、コマンドを実行したり、、、、、、...などの一部のエンコーディングで改行文字を指定できる言語ruby
またはインタプリタを呼び出すことができます。python
ksh93
zsh
bash
すでに持っているのでruby
:
ruby -e 'exec "env", "FOO=a\n\n\nb", *ARGV' -- ruby -e 'puts ENV["FOO"]'
ただし、すべての系譜プログラミング言語はruby
独自に環境変数を設定できるため、以下を行う必要はありませんenv
。
ruby -e 'ENV["FOO"]="a\n\n\nb"; exec *ARGV' -- ruby -e 'puts ENV["FOO"]'
答え4
値にリテラル改行を使用します。
$ env FOO="hello
world" ruby -e 'puts ENV["FOO"]'
出力:
hello
world
文字列を実際の改行文字に変換するには、\n
次のユーティリティを使用しますprintf
。
$ env FOO="$(printf "%b" 'hello\nworld')" ruby -e 'puts ENV["FOO"]'
hello
world
env
これに関して特別なことはありません(実際のenv
プロセスが開始される前に拡張されたため、実際の改行文字のみが表示されます)。