コンテキスト:https://stackoverflow.com/a/372 53784/15603477
cmd='printf "%s\n" "$(date -d "$variable" +%c)"'
echo ${variable}
返品2010-09-08 12:34:56
echo "$cmd"
返品printf "%s\n" $(date -d "$variable")
echo "${cmd}"
返品printf "%s\n" $(date -d "$variable")
bash -c "$cmd"
次に、回答に示すように次のコマンドを実行します。
Fri
Dec
24
00:00:00
IST
2021
見つかった内容は次のとおりです。
- https://stackoverflow.com/questions/20858381/what-does-bash-c-do
- https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Invoking-Bash
オプションではなく、最初の引数command_stringからコマンドを読み取り、実行して終了します。 command_stringの後に引数がある場合、最初の引数は$ 0に割り当てられ、残りの引数は位置引数に割り当てられます。 $ 0の指定は、警告メッセージとエラーメッセージに使用されるシェルの名前を設定します。
私の質問は最後のコマンドbash -c "$cmd"
、出力についてです。今日(現在2021年12月24日です。)どこから来ましたか?
--更新:確認しました。https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#eval、https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Bourne-Shell-Builtins、https://man7.org/linux/man-pages/man1/bash.1.html
次の引用は私が見つけたものです。eval
eval [arg ...]引数を読み取り、それを単一のコマンドで連結します。その後、シェルはコマンドを読み取り、実行し、その終了ステータスはeval値として返されます。もし
答え1
シェルコードは3つのパラメータを使用してコマンドをbash -c "$cmd"
実行します。bash
bash
-c
$cmd
可変内容
bash
これらのシェルを呼び出すことは、3番目の引数のコードを解釈する標準的な方法です(ただ1以外のすべてのシェルがこれを行います)。
$cmd
ここでは、次のように初期化されると言います。
cmd='printf "%s\n" "$(date -d "$variable" +%c)"'
ただし、出力には次echo "$cmd"
のように割り当てられたものが表示されます。
cmd='printf "%s\n" $(date -d "$variable" +%c)'
したがって、新しい呼び出しによって解釈されるシェルコードは次bash
のようになります。
printf "%s\n" $(date -d "$variable" +%c)
これでbash
新しい通訳が始まるので、$variable
そこには割り当てられません。代わりにbash -uc
(と同じbash -o nounset -c
)を実行すると、-c
次のようになります。
bash: line 1: variable: unbound variable
このnounset
オプションがないと、設定されていない変数は空のように拡張されるため、date
次の引数を使用してコマンドを呼び出します。
date
-d
- 公理
+%c
-d
標準date
オプションではありません。 GNUの場合、date
入力日を指定するために使用されます。入力日が空の場合、date -d 0
またはdate -d 00:00:00
、つまり今朝00:00:00と同じです。
$(date...)
参照がなく、リストコンテキスト(コマンドprintf
引数)にあるため、分割+globの影響を受けます。分割は空白、タブ、および改行文字を含むbashのデフォルトの日付出力を中断するため、出力でスペースで区切られた各単語に対して生成された別々の引数を見ることができます$IFS
(ワイルドカード部分はここで何もしません)実行しません)出力にワイルドカード文字はありません。printf
date
date
したがってdate
、次のように出力すると、次のパラメータを含む呼び出しがFri Dec 24 00:00:00 IST 2021
発生します。printf
printf
%s\n
Fri
Dec
00:00:00
IST
2021
すべての引数を使用するためにできるだけ多くの形式をprintf
再利用し、最終的にすべての引数を別々の行に印刷します。%s\n
bash
今この新しいインスタンスが必要な場合継承するこれを呼び出すシェルの場合、後で呼び出す各コマンドの環境にこの変数を追加でき$variable
ます。export
export variable
bash -c "$cmd"
(printenv variable
、 perl -E 'say $ENV{variable}'
…も見ることができます)。
またはbash
³ を一度だけ呼び出すには:
(export variable; exec bash -c "$cmd")
または:
variable=$variable bash -c "$cmd"
存在する
eval "$cmd"
現在、シェルには解釈のコードが渡され、$cmd
呼び出し内でディスパッチされたシェルなので、$variable
その内容にアクセスできるため、環境にエクスポートする必要はありません。
¹これは、実際にはシェル言語と見なすことができない他の言語の一部の通訳者にも当てはまります。python
たとえば、一部は他のオプションを使用します(たとえば、、、sed -e 'sed code'
... perl -e 'perl code'
、php -r 'php code'
またはまったくオプションなし)awk 'awk code'
。sed 'sed code'
²と$0
はに設定されておりbash
、ここの位置パラメータのリストは空です。
bash
3およびインスタンスが独自に実行するコマンド
答え2
この変数で定義されたコマンドは、名前付き$cmd
変数を参照します$variable
。$cmd
他のプロセスの新しいシェル呼び出しに渡されると、$cmd
この変数は実行時に設定されません。したがって、日付インポート呼び出しの結果は、date -d "" +%c
現在の日付を返すことです。
コーディングの観点から、コマンドを変数に格納するのは悪い習慣です。あなた〜する近いうちに、引用の悪夢に陥るでしょう。変数をデータとして、関数をコードとして使用してください。
cmd() {
local v=$1
printf "%s\n" "$(date -d "$v" +%c)"'
}
variable="2010-09-08 12:34:56"
cmd "$variable"
最後に、妥当な理由がない限り、変数を使用するときは常に二重引用符で囲む必要があります。 (echo $variable
悪い、echo "$variable"
より良い、printf "%s\n" "$variable"
最高。)