awk
コマンドをawk
コマンド内で使用しようとしましたが成功しませんでした。 div id = “1a680191bd”>
ループ。
awk
で切り取りたい一連の文字列を含む変数があります。データを取得します。
その方法は知っていますが、本当に必要なのはデータを連続してカットすることです。
つまり、この変数を取得しました:
var="data1,data2,data3"
そして今ここにいます:
for ((i=1; i<=3; i++)) do echo $(awk -F, "{print $1}" <<< $var) done
$1
ループ$i
によるが、成功しなかった。
コメント
回答
自分の目的を達成できますawkスクリプトで二重引用符を使用してシェル変数を挿入しようとしています。それでも、1つのリテラル$
を保持する必要があります。これは、バックスラッシュでエスケープすることで実行できます。 :
echo $(awk -F, "{print \$$i}" <<<$var)
これにより、$i
が1
に展開されます。各反復で2
と3
が表示されるため、awkには$1
、
と$3
を使用すると、各フィールドが展開されます。
もう1つの可能性は、シェル変数を-v
フラグを使用したawk変数:
echo $(awk -F, -v i="$i" "{print $i}" <<<$var)
これにより、awk変数 i が同じ名前のシェル変数の内容に割り当てられます。 awkの変数は、フィールドに使用される$
を使用しないため、 iを参照するには$i
で十分です。 – i がawkの変数である場合のthフィールド。
-v
を使用してawk変数を割り当てる方が一般的に安全です。特に、任意の文字シーケンスを含めることができる場合は、その場合、コンテンツが意図に反してawkコードとして実行されるリスクが少なくなります。ただし、あなたの場合、変数は単一の整数を保持するため、「それほど心配する必要はありません。
さらに別のオプションは、awk自体でfor
ループを使用することです。 。その方法の詳細については、awkのドキュメントを参照(またはこのサイトを検索)してください。
コメント
- …または入力レコードを設定しますセパレータを適切に
awk -v RS='[,\n]' 1 <<< "$var"
(またはより移植性の高いprintf "$var" | awk -v RS=, 1
) - @steeldriverそのawkスクリプトは、次の3つのフィールドすべてを出力します。 OPがそれだけを実行していることを考えると、これは問題ありません…シェルループで他のコマンドを実行することに関心があるという前提で、単一のフィールドを抽出することに答えを集中することになりました(そもそも1つを使用する動機になっています…)
- 理解しました-'が、OPについてコメントして本当にやりたい;)
- first は注入(およびセキュリティ上の懸念)であり、 second o ne(
-v
を使用)はインジェクションではありません。 - ありがとうございます。あなたの答えで私の問題は解決しました!何年にもわたって投稿を読んだ後、初めてここに質問を投稿します。がっかりしていません。すばらしいコミュニティです!
回答
awk
を使用しているようですこの状況では過剰ですが、tr
とwhileループはどうですか:
tr , "\n" <<<"$var" | while read; do echo $REPLY done
出力:
data1 data2 data3
コメント
- すばらしい。
REPLY
はread
組み込みシェルコマンドのデフォルトのname
引数です。 - これには、シェルがデフォルトの変数を使用して
read
からデータを入力する必要があることに注意してください。これは、bash
が行うことです。 、しかしこれは標準ではありません。また、read
コマンドは、データに円記号が含まれている場合にデータを変更したり、値から隣接する空白を削除したりする場合があります。また、改行が埋め込まれた値を複数の値として読み取ります。さらに、シェルが値を分割したり、ファイル名の展開を実行したりしないようにするには、"$REPLY"
が必要です。
回答
awk は受け入れることができますj
(変数として)と$j
(フィールドインデックスとして)の両方:
for i in 1 2 3; do echo "$var" | awk -v j=$i -F , "{print $j}"; done
$i
の例では” confused “awk
どちらを使用するか(シェルまたはそれ自体の変数-優先)両方が$
プレフィックスで参照されます。
注
sh 「ポータブル」スクリプトの標準であるシェルはサポートしていません:
(( i=1; i<=3; i++; ))
および<<< $var
コンストラクト
また、for
でseq
コマンドを使用することを検討してください。 div>ループは、可能な場合、数列生成をより細かく制御します。
コメント
- ループは、3つのファイルが呼び出された場合にのみ機能します。 、
2
および3
。また、シェルで引用符で囲まれていない変数展開を使用すると、データにファイル名パターン(*
など)が含まれている場合に望ましくない結果が生じる可能性があります。echo
は、バックスラッシュが含まれている場合、データをさらに変更する可能性があります。
回答
#!/bin/sh var="data1,data2,data3" unset data while [ "$var" != "$data" ]; do data=${var%%,*} # delete first comma and the bit after it var=${var#*,} # delete bit up to first comma (and the comma) printf "data = "%s"\n" "$data" done
ここでは、変数置換を使用して、var
変数の値から連続する各コンマ区切りデータフィールドを取得します。ループ内のdata
への最初の割り当ては、最初のカンマの後の$var
からすべてを削除します。次に、var
変数が変更され、最初のカンマまでの最初のビットが削除されます。
これは、"$var" = "$data"
は、文字列に対してこれ以上何もできないことを意味します。
この方法では、改行が埋め込まれたカンマ区切りのデータ文字列を処理できます。
var="line1 line2,data2,last bit goes here"
var
に上記の値を指定すると、上記のスクリプトは出力されます
data = "line1 line2" data = "data2" data = "last bit goes here"
埋め込まれた改行を気にしない。 めったに awk
の呼び出しをループする必要はありません。
awk
に注意してください。文字列をカンマ区切りのフィールドのセットとして読み取ることができ、次の項目をループできることを完全に嬉しく思います。
printf "%s\n" "$var" | awk -F "," "{ for (i=1; i<=NF; i++) print $i }"
var="data1,data2,data3"
、これは印刷されます
data1 data2 data3
変数は、$var
値をビットに分割し、set -f
を使用してファイル名の展開を無効にします:
set -f oldIFS=$IFS; IFS="," set -- $var IFS=$oldIFS; unset oldIFS set +f for data do printf "data = "%s"\n" "$data" done
echo "${var//,/$'\n'}"
を使用できます)