arg がファイルであることを確認し、それに応じて印刷します。

arg がファイルであることを確認し、それに応じて印刷します。

arg 経由またはファイルが存在しない場合は、stdin からファイルを受け取る次のコードがあります。

file=
column=
pattern=
path=
cmd="echo"

while getopts "f:c:e:" opt; do
        case $opt in
                f) file="$OPTARG";;
                c) column="$OPTARG";;
                e) pattern="$OPTARG";;
                *) echo "Usage: $0 -f [file] -c [column] -e [pattern]"
        esac
done

if [ -z "$file" ]; then
        file=$(cat)
fi

このアプローチの問題は、catがファイルではなくファイルでは機能しないことです。たとえば、stdoutからインポートした場合:

cat data.csv | ./read.sh -c 2 -e " Max"

これにより、次のことは実行できません。

cat "$file"

Bashスクリプトでは代わりにechoを使用する必要があります。

OTOH、ファイルであればcatを使用でき、すべてが大丈夫です。私の質問は、スクリプトがvar $fileが実際のファイル名かstdoutであるかを認識させる方法です。

編集:コメントと回答を考慮し、ユーザーが指定した列と正規表現を読み、標準入力または引数として渡されたファイルで考慮できるスクリプト全体をユーザーに提供する方法は次のとおりです。

#!/bin/bash

unset -v column pattern filepath
cmd=echo

DELIMITER=","

while getopts "f:c:e:" opt; do
        case $opt in
                f) file="$OPTARG";;
                c) column="$OPTARG";;
                e) pattern="$OPTARG";;
                *) printf>&2 '%s\n' "Usag: $0 [-f file] [-c column] [-e pattern]"; exit 1
        esac
done

if [ -z "$file" ]; then
        file=$(cat)
elif [ -z "$column" ]; then
        echo "column number neeeded!"
elif [ -z "$pattern" ]; then
        echo "pattern needed!"
fi

if [ -f "$file" ]; then
        cmd="cat"
fi

if [ "$column" -eq 5 ]; then
        DELIMITER=":"
fi

"$cmd" "$file" | awk -v col="$column" -v pattern="$pattern" -v del="$DELIMITER" -F "$DELIMITER" '{
        for (i=1;i<=NF;i++) {
                if ( i == col && $i == pattern ) {
                        print $0
                } else if ( del == ":" && $i == pattern ) {
                        print $0
                }
        }       
}'

exit 0

動作しますが、正しいアプローチではないと確信しています。私のファイルで両方の操作を実行しようとしました。

cat data.csv | ./read.sh -c 2 -e "Max"

そして:

./read.sh -f data.csv -c 2 -e "Max"

上記のスクリプトは動作しますが、最適化はゲームの名前です!

ベストアンサー1

の場合はcat標準-入力を意味します。多くのシステムでは、このコマンドは同様/dev/stdinにすべてのコマンドで動作しますが、catLinuxまたはCygwinでは/dev/stdinstdinで開かれた同じファイルを指し、場合によってはstdinとまったく同じようには機能しません。

だからあなたはこれを行うことができます:

file=-
unset -v column pattern filepath
cmd=echo

while getopts f:c:e: opt; do
  case $opt in
    (f) file="$OPTARG";;
    (c) column="$OPTARG";;
    (e) pattern="$OPTARG";;
    (*) printf>&2 '%s\n' "Usage: $0 [-f file] [-c column] [-e pattern]"; exit 1
  esac
done
shift "$(( OPTIND - 1 ))"

cat -- "$file"

stdin()は一度だけ読むことができます-

また注:

  • エラーはstderrに送信する必要があります。
  • echo$0任意のデータ(制御できないデータなど)には使用できません。
  • [...]同意したようにメッセージを使用してください。任意に選択できるしたがって、この場合は必須であることを示唆しています-f [file]が、その引数はオプションなので、ここでは正しくありません。-f
  • pathスクリプトが最終的に解釈される可能性がある場合zshshシミュレーションでない場合)、配列$path変数に/$PATHに似た変数名を指定しないでください。cshtcsh
  • パラメータが指定されていることを確認するには、nullテストを避ける必要があります。たとえば-f ''、代わりに初期化時に使用して変数が設定されていないことを確認し、後でまだ設定されていないことを確認します。あるいは、追加のブールフラグ変数を使用して、オプションが合格したかどうかを記録します。$file-funset -v var[ -z "${var+set}" ]
  • -ユーザーがstdin以外の現在の作業ディレクトリから呼び出された実際のファイルを意味するファイルを渡すことを許可するには、それをハンドルに変換できます。-./-(f)
  • file=$(cat)stdinで読み取ることができる内容を読み、それをfile変数(メモリ内)に保存します。したがって、他の人が言ったように、変数名は取得する入力ファイルの内容であるため、少し誤解を招く可能性があります。しかしそれも壊すあなたが得ることは、$(...)NUL文字を削除またはブロックするzshを除いて、すべての末尾の改行文字を削除したことです。echoそれを(任意のデータではなく)使用すると、自分でechoダメージを受けます。

ここでは逆のアプローチをとり、-fstdinに引数として渡されたファイルを開くこともできます。

unset -v column pattern filepath
cmd=echo

while getopts f:c:e: opt; do
  case $opt in
    (f) exec < "$OPTARG";;
    (c) column="$OPTARG";;
    (e) pattern="$OPTARG";;
    (*) printf>&2 '%s\n' "Usage: $0 [-f file] [-c column] [-e pattern]"; exit 1
  esac
done
shift "$(( OPTIND - 1 ))"

cat

execファイルを開くことができない場合、POSIX シェルは自動的に終了します。-f割り当て時など、複数のオプションが渡された場合は、最後のオプションのみが考慮$fileされます。

おすすめ記事