関数やスクリプトから*実際*(解釈されていない)シェル引数を取得する方法はありますか?

関数やスクリプトから*実際*(解釈されていない)シェル引数を取得する方法はありますか?

posix私はWindowsのGit bashシェルでDOSスタイルパスを通常のUnixスタイルパスに変換する関数を使用しています。 DOSスタイルパスはバックスラッシュを区切り文字として使用するため、シェルがバックスラッシュを使用して次の文字をリテラルとして表示しないように、パスパラメータを引用する必要があります。得る方法はありますか?説明できない私の関数の内部のパラメータなので、引用する必要はありませんか?

役に立つなら、私の機能は次のとおりです。

function posix() {
  echo $1 | sed -e 's|\\|/|g' | sed -re 's|^(.)\:|/\L\1|'
}

(ところで、何でも大歓迎ですコメント引用/シェル解釈のトラブルシューティングに関連しない他の方法で機能を改善するためのヒントもあります。 )

答え1

解釈されていないシェルパラメータにはなどが含まれます$1$2ほとんどの場合、パラメータ値の追加の拡張を防ぐには、拡張を二重引用符で囲む必要があります。"$@"すべてのパラメータのリストを提供します。

たとえば、シェルスクリプトの引数を関数に渡すには、次のように呼び出します。

first_argument_as_filename_in_unix_syntax=$(posix "$1")

二重引用符が必要です。を書くと、posix $1最初の引数の値ではなく、最初の引数の値に対してトークン化とワイルドカードを実行した結果が渡されます。また、スクリプトを呼び出すときに正しい参照を使用する必要があります。たとえば、bashで次のように書くとします。

myscript c:\path with spaces\somefile

これにより、解釈されない実際のパラメータは、 と にmyscriptなります。だからしないでください。c:pathwithspacessomefile

あなたのposix機能が間違っています。もう一度二重引用符がないためです$1変数とコマンドの置換は常に二重引用符("$foo"、)で囲まれています"$(foo)"実際、引用符を必要としない例外を覚えておくよりも、この規則を覚えておく方が簡単です。

echo場合によっては、独自の処理を実行し、外部プロセス呼び出しが遅くなります(特にWindowsでは)。 bashで完全なプロセスを実行できます。

posix () {
  path="${1//\\//}"
  case "$path" in
    ?:*) drive="${p:0:1}"; drive="${drive,}"; p="/$drive/${p:2}";;
  esac
  printf %s "$p"
}

jw013で述べたzsh関数あなたが思うようにはなりません。noglobコマンドの前に置くことができ、zshは引数にワイルドカードを割り当てます(ファイル名の生成、つまりワイルドカード拡張など)。たとえば、zshでは、noglob locate *foo*bar*を書くとlocateパラメータを使用して呼び出されます*foo*bar*。通常、エイリアスnoglobの後に組み込み機能を非表示にします。この機能は、実行しようとしている操作とは関係ありません。

答え2

言及した方法で「解釈されていない」シェル入力を受け取ることができないことを指摘する他の答えは正しいかもしれませんが、この可能性を断固として拒否することは間違っています。シェルに解釈しないように指示すると、当然、シェルが解釈する前に受け取ることができます。 Simple POSIXを使用すると、heredocこれは非常に簡単になります。

% sed -e 's@\\@/@g' -e 's@\(.\):\(.*\)@/drive/\1\2@' <<'_EOF_'     
> c:\some\stupid\windows\place
> _EOF_
/drive/c/some/stupid/windows/place

編集1:

これらの文字列をシェルパラメータとしてシェル関数に渡すには、それをシェル変数に保存する必要があります。通常、単に幸運ではないかもしれませんが、var=<<'HEREDOC'POSIXは組み込み-rパラメータを指定しますread

% man read

POSIX プログラママニュアル

...

デフォルトでは、バックスラッシュ( '\')は、-rオプションが指定されていない限り、エスケープ文字(バックスラッシュ)で説明されているようにエスケープ文字として機能する必要があります。標準入力がターミナルデバイスで、呼び出されるシェルが対話型の場合、次の場合にはreadに連続行を求めるメッセージが表示されます。

  • -r オプションを指定しない場合、シェルはバックスラッシュで終わる入力行を読み込みます。

  • ここでは、新しい行を入力しても文書は終了しません。

組み合わせると、最初は直感的ではないかもしれませんが、マイナーで移植可能ですreadheredoc

% _stupid_mspath_fix() { 
> sed -e 's@\\@/@g' -e 's@\(.\):\(.*\)@/drive/\1\2@' <<_EOF_
>> ${1}
>> _EOF_
> }
% read -r _stupid_mspath_arg <<'_EOF_'                    
> c:\some\stupid\windows\place
> _EOF_
% _stupid_mspath_fix ${_stupid_mspath_arg}
/drive/c/some/stupid/windows/place

編集2:

heredocsおそらく2番目の例では、2つの間の違いを見つけたでしょう。heredoc _EOF_関数内の終端子は引用されていませんが、入力終端子は一重引用符で囲まれていますread。このようにして、シェルは引用符で囲まれheredocていない終端子ペアを使用して拡張を実行するように指示されますが、終端子が引用されるときはそうしないように指示されます。関数で引用符のない内容を展開すると、拡張する変数heredocの値がすでに引用符付き文字列に設定されており、それを2回解析しないため、中断されません。

おそらくあなたが望むのは、1つのコマンドの出力から別のコマンドの入力にWindowsパスを動的に渡すことです。のコマンド置換により、heredoc以下が可能になります。

% _stupid_mspath_fix() { 
> sed -e 's@\\@/@g' -e 's@\(.\):\(.*\)@/drive/\1\2@' <<_EOF_
>> ${1}
>> _EOF_
> }
% read -r _stupid_mspath_arg <<'_EOF_'                    
> c:\some\stupid\windows\place
> _EOF_
% _stupid_mspath_fix ${_stupid_mspath_arg}
/drive/c/some/stupid/windows/place    
% read -r _second_stupid_mspath_arg <<_EOF_                    
> $(printf ${_stupid_mspath_arg})
> _EOF_
% _stupid_mspath_fix ${_second_stupid_mspath_arg}
/drive/c/some/stupid/windows/place

したがって、デフォルトで1つのアプリケーション(printf上記で使用したもの)からバックスラッシュを確実に出力できる場合は、そのコマンドを内部的に実行して別の$(...)アプリケーションに渡すと、heredocバックスラッシュをアプリケーション(たとえば上記のアプリケーションなど)に対して引用されreadていませんsed。バックスラッシュを完全に解析しないでください。アプリケーションがバックスラッシュを入力/出力として扱うことができるかどうかを直接調べる必要があります。

質問と厳密には関係ありません。

Gillesの答えでは、彼は${var/search/replace}素晴らしかったがPOSIXではなくパラメータ拡張フォーマットを推奨しました。これは本当に屈辱的なことです。それは私にとって重要ではありませんが、彼の編集では、彼はposix ()何人かの人々に誤解を招く可能性がある関数名を保持しました。

この時点で、元の投稿のposix ()関数は非常に便利な拡張正規表現sed -r引数を使用しますが、残念ながらそれもPOSIXではありません。 POSIXは拡張正規表現パラメータを指定しないため、その使用はsed信頼できない可能性があります。

マイアカウントほんの数日前、Stack OverflowにPOSIXパラメータ拡張を具体的に扱ういくつかの答えを投稿しました。 POSIXガイドを参照して、リンクした自分のプロフィールページでリンクを見つけることができます。また、私が実演している他の用途も見つけることができますheredoc。たとえば、シェルスクリプト全体をシェル変数として読み込み、プログラムで解析して操作し、最後に他のスクリプトやシェル関数内で新しいバージョンを実行するなどの操作を実行します。ちょうど言うよ。

答え3

シェルプロセスを持つことはできません」説明できない「入力。コマンドラインに入力する内容はシェルで解釈される文字列だけです。シェルでテキスト、入力した文字を関数やコマンドに渡すことはできません。持つこれを解釈して、どのコマンド/関数を呼び出し、どのパラメータを使用する必要があるかを調べてください。コマンドプロンプトに入力するときは、シェルの解釈規則に従って入力する必要があることを認識する必要があります(シェルを使用しているためです!)。

シェル解析ルールを選択することは非常に便利です。これは邪魔になりませんが、むしろランダムな引数の指定など、必要なすべての操作を実行するようにシェルに指示する方法を提供します。解釈がないと、シェルは入力で実行する正確な操作を抽出できません。解釈は、エスケープなしでコマンドに渡すことができない特殊文字(スペースなど)を意味します。

説明そのものについてはいつも見つけました。バッシュ文書これはとても良いです。つまり、チルダ拡張のようなことは非常に早く起こります(そしてチルダ拡張は特定の状況でのみ起こります)。その後、変数の置換とトークン化が発生し、最後にワイルドカードが発生します。

関連情報