Bashスクリプトからパラメータ「AS IS」を取得するには?

Bashスクリプトからパラメータ「AS IS」を取得するには?

readvar.shというスクリプトがあります。

#! /bin/bash
a="$1"

echo "$a"

パラメータを取得したいです。文字通りユーザーが入力すると、

たとえば、ユーザーが次を実行する場合:./readvar.sh \\

\\パラメータの周囲に引用符なしで出力する必要があります。

それは可能ですか?

答え1

一般的に言えば、これはできません。

runの場合、./readvar.sh \\コマンドが書かれたシェルはコマンドラインを解析し、スペースを単語区切り文字として認識し、バックスラッシュを次の文字(別のバックスラッシュ)を引用することを認識します。その後、./readvar.sh2つの単語で終わり、\プログラムを起動して./readvar.shその2つの単語をプロセスを開始するパラメータのリストに入れます。 (コマンド名はargv[0]Cプログラムに出てくるパラメータ#0です。)

./readvar.sh '\'ユーザーがPerlプログラムなどを使用してスクリプトを入力または起動すると、同様のbs='\'; ./readvar "$var"結果が得られます。system("./readvar.sh", "\\");スクリプトには通常、何が起こっているのかを知る方法はありません。


あなたができることは、シェル入力に適した形式ですべての引数を印刷することです。たとえば、Bashでは次のように使用します。

if [ "$#" -ne 0 ]; then
    printf "%q " "$@"
fi
echo 

出力はBashで動作しますが、$'\n'改行などの形式で引用符を使用するため、標準シェルでは機能しない可能性があります。また、スクリプトを\\使用または起動するたびに出力されます。\\'\'"\\"

Bashでもこれを乱用する可能性がありますextdebug。これは、実行中のコマンドのコンテキストに、BashのDEBUGトラップに表示されるコマンドラインを配置します。

export CMDLINE
trap 'CMDLINE=$BASH_COMMAND; true' DEBUG
shopt -s extdebug

ただし、そこにあるコマンドラインは拡張されていないため、実行すると代わりに拡張値がenv abc=$var |grep CMD表示されます。env abc=$var

もちろん、追加の手順を実行する Bash シェルでコマンドが実行されない場合は機能しません。プロセスツリーの親にこれらのシェルがある場合は、前のCMDLINEコマンドを実行するコマンドとして設定できます。


今、これらのトリッキーな回避策が存在しますが、スクリプトユーザーがスクリプトが最終的に実行する必要があるタスクを達成するために他の方法を使用する方が良いと驚くべきことではないかもしれません。

答え2

readフラグを使用して呼び出すことができます-r

-r  Backslash does not act as an
    escape character.  The backslash
    is considered to be part of the line.
    In particular, a backslash-newline pair
    may not then be used as a line
    continuation.

だから:

IFS="" read -r a
echo "$a"

「\」を入力すると、「\」がエコーされます。また、スペースを保存します(ターゲットでない場合はIFSビットを削除できます)。

パラメータとして渡すには、単一引用符を使用して値を変更せずに残す必要があります。

./readvar.sh '\\'

var.shを読む:

#!/bin/bash

IFS="" read -r a
./usevar.sh "$a"

var.shを使用してください。

#!/bin/bash

echo "$1"

と入力する\\とエコーさreadvar.shれます。usevar.sh\\

テキストの先頭と末尾のスペースを維持するには、IFS が必要です。

関連情報