パラメータまたはパイプの入力を可能にするBash関数

パラメータまたはパイプの入力を可能にするBash関数

パラメータやパイプから入力を受け取ることができるように、次のbash関数を作成したいと思います。

b64decode() {
    echo "$1" | base64 --decode; echo
}

必須使用:

$ b64decode "QWxhZGRpbjpvcGVuIHNlc2FtZQo="
$ b64decode < file.txt
$ b64decode <<< "QWxhZGRpbjpvcGVuIHNlc2FtZQo="
$ echo "QWxhZGRpbjpvcGVuIHNlc2FtZQo=" | b64decode

答え1

バラよりStefan Chazerasの答えより良い解決策を得るために。


/dev/stdin以下を使用して標準入力から読み取ることができます。

b64decode()
{
    if (( $# == 0 )) ; then
        base64 --decode < /dev/stdin
        echo
    else
        base64 --decode <<< "$1"
        echo
    fi
}
  • $# == 0コマンドライン引数が0であることを確認してください。
  • base64 --decode <<< "$1"使用やパイプのherestring代わりに使用することも可能です。echobase64

答え2

ここでは、次のようにする必要があります。

b64decode() {
  if [ "$#" -gt 0 ]; then
    # concatenated arguments fed via a pipe.
    printf %s "$@" | base64 --decode
  else
    base64 --decode  # read from stdin
  fi
  ret=$?
  echo # add one newline character
  return "$ret" # return with base64's exit status to report decoding
                # errors if any.
}

とにかくいいえ使用base64 --decode < /dev/stdin。せいぜい(ほとんどのシステムでは)何もせずに(fd 0をfd 0にコピーし、操作なし)と< /dev/stdin同じことを行います。dup2(0,0)

しかし、LinuxやCygwinでは< /dev/stdinこれは正しく機能しません。これらのシステムでは、オープンは/dev/stdinstdinのコピーと同じではありません。最初からもう一度開き、現在stdinで開いているファイルと同じファイルを独立して開きます。

したがって、以前にstdinがいくつかの一般的なファイルの途中を指していた場合、後で< /dev/stdinstdinが現在指している結果が得られます。最初にファイルの。 stdinがパイプの書き込み終了(通常の状況ではあってはいけません)の場合、最終的には読み取り終了になります。ソケットの場合、ソケットは不可能なので失敗します。開いている。読み取り用にファイルを開く権限がない場合も同様です(たとえば、権限が変更されたか、ファイルが元々別の資格情報を使用してstdinで開かれたため)。

戻り値は、base64 --decode < /dev/stdinファイル内のstdinの現在の場所(検索可能なファイル入力の場合)は、最後(またはbase64読み取りが停止する場所)に残っておらず、変更されていません。なぜならbase64の stdin が別の位置にあるからです。ファイル説明を開く

答え3

サンディップの答えbase64これは、ユーティリティが複数行をサポートしていないために機能します。より一般的なケースに対するより一般的な修正

そうですか?

my_function() {
    if (( ${#} == 0 )) ; then
        while read -r line ; do
            target_utility "${line}"
        done
    else
        target_utility "${@}"
    fi
}

答え4

両方サンディップそしてトム・ローチ答えは啓発的で感謝していますが、target_utility "${@}"状況に応じてより複雑なコードを表すことができます。if重要なコードを内部および外部に複製すると、else不要な問題が発生する可能性があります。 OPの質問は再帰を使用して完全に解決される問題を提示できないかもしれませんが、他の読者の質問はそれを使用するか、ラッパー機能を使用することを考慮すると役に立ちます。

my_function() {
    if (( ${#} == 0 )) ; then
        while read -r __my_function ; do
            my_function "${__my_function}"
        done
    else
        target_utility "${@}"
    fi
}

この回答は、「引数またはパイプの入力を可能にする Bash 関数」に可能なさまざまなソリューションの 1 つです。 OPは[コメントから]これがbase64実際の問題ドメインではないと指摘したからです。したがって、ファイルから直接入力を読み取ることができることを確認しようとしません。

さまざまな意見によれば、これらのテンプレートと同様のその他のテンプレートは、先行するスペースを含む行を正しく処理できない可能性がありIFS =ますread。実際にシェルに機密文字がある場合は、この関数を呼び出す前に特別な処理が必要になる場合があります。現状のまま、コードは先行スペースが発生しないことが知られており、データの感度がエミッタによって前処理されている場合はうまく機能します。

これは単なる教科書の例ではありません。実際の制作スクリプトで使用されます。 target_utility実際のコードスニペットの簡単な名前です。この回答はユニバーサルテンプレートを想定せず、追加の開発者の知恵を必要としません。

(ユーザーは通常、回答をそのまま使用するのではなく、時々回答を調整すると仮定するのが合理的に見えます。)

関連情報