私は次のテキスト行を作成しました。
INSERT INTO radcheck(id, username, attribute, op, value) VALUES (,,00:23:32:c2:a9:e8,Auth-Type,:=,Accept);
sedを使って次のようにしたいと思います。
INSERT INTO radcheck(id, username, attribute, op, value) VALUES (,'','00:23:32:c2:a9:e8','Auth-Type',':=','Accept');
これは文脈でより意味があり、過去17時間(明らかに)これについてもっと学びました。
#!/bin/bash
ssh [email protected] brmacs >>MACS.txt mv MACS.txt /etc/persistent scp [email protected]:/etc/persistent/MACS.txt MACS.txt
sed -i "1d" MACS.txt
head -c 58 MACS.txt >>shortmacs.txt
tail -c 18 shortmacs.txt >>usermac.txt
sed 's/"//g' usermac.txt >>usermacrdy.txt
sed -i 's/^/INSERT INTO `radcheck`(`id`, `username`, `attribute`, `op`, `value`) VALUES (,'',/' usermacrdy.txt
sed "s/$/','Auth-Type',':=','Accept');/" usermacrdy.txt > sqlquery.txt
sed -i "s/,,/\,\'\',\'/" sqlquery.txt
rm -f MACS.txt
rm -f shortmacs.txt
rm -f usermac.txt
rm -f usermacrdy.txt
働く! ! !
ヘッダーとトレーラーはUBNT CPEデバイスから送信された生のテキストファイルからMACアドレスを切り取り、sedを介してMACアドレスの周りにSQL構文を構築します。
id
結局、クエリの一部が成功するために必要ではないことがわかったので、今や少し同じ状況にあります。
sed -i 's/^/INSERT INTO `radcheck`(`username`, `attribute`, `op`, `value`) VALUES (/' usermacrdy.txt
sed "s/$/','Auth-Type',':=','Accept');/" usermacrdy.txt > sqlquery.txt
sed -i "s/\,\'\',\'//" sqlquery.txt
答え1
必要な一重引用符を含める方法は4つあります。
一重引用符文字列内で一重引用符文字列をエスケープすることはできません。ただし、引用符で囲まれた文字列を終了し、エスケープされた単一引用符を挿入して、新しい単一引用符で囲まれた文字列を開始できます。したがって、中間に一重引用符を入れるには、次のように'ab'
します'a'\''b'
。または、必要なsedコマンドを使用してください。
$ sed -r 's/,([^ ),]+)/,'\''\1'\''/g; s/,,/,'\'\'',/g' file
INSERT INTO radcheck(id, username, attribute, op, value) VALUES (,'','00:23:32:c2:a9:e8','Auth-Type',':=','Accept');
2番目の方法は、二重引用符で囲まれた文字列を使用することです。この場合、単一引用符を簡単に挿入できます。
$ sed -r "s/,([^ ),]+)/,'\1'/g; s/,,/,'',/g" file
INSERT INTO radcheck(id, username, attribute, op, value) VALUES (,'','00:23:32:c2:a9:e8','Auth-Type',':=','Accept');
二重引用符で囲まれた文字列の問題は、シェルがこれを処理する方法です。しかし、ここにはシェルアクティブ文字がないので簡単です。
3番目の方法は、PM2Ringに示されているように16進エスケープを使用することです。
コメントでJonathan Lefflerが提案した4番目のアプローチは、sed
コマンドを別々のファイルに保存することです。
$ cat script.sed
s/,([^ ),]+)/,'\1'/g
s/,,/,'',/g
$ sed -rf script.sed file
INSERT INTO radcheck(id, username, attribute, op, value) VALUES (,'','00:23:32:c2:a9:e8','Auth-Type',':=','Accept');
この方法の利点は、sed
シェルの干渉なしにコマンドを直接読み取ることができることです。これにより、シェルアクティブ文字をエスケープする必要がなくなり、コマンドを純粋な構文で入力できるようになりますsed
。
ソリューションsed
の仕組み
ヒントは、目的のカンマ区切り文字列の周りに一重引用符を付け、他の文字列の周りには入れないことです。提供された単一の例に基づいて、1つのアプローチは次のとおりです。
s/,([^ ),]+)/,'\1'/g
カンマの後にスペースがなく、カンマがなく、右角かっこではない文字が1つ以上検索されます。これらの文字は一重引用符で囲まれています。
s/,,/,'',/g
連続したカンマを見つけ、その間に2つの単一引用符を配置します。
OSXおよびその他のBSDプラットフォーム
さらにバックスラッシュを避けるために、上記の式ではsed
拡張正規表現を使用します。 GNUの場合は呼び出されますが、-r
BSDの場合は呼び出されます-E
。さらに、一部の非GNUはsed
セミコロンで区切られた複数のコマンドを許可しません。したがって、OSXでは、次のことを試してみてください。
sed -E -e "s/,([^ ),]+)/,'\1'/g" -e "s/,,/,'',/g" file
付録:MACアドレスの一致
コメントから次の情報を入手できます。
$ cat file3
INSERT INTO radcheck(username, attribute, op, value) VALUES (00:23:32:c2:a9:e8,'Auth-Type',':=','Accept');
また、開いている括弧の後のMACアドレスの周りに一重引用符を入れようとします。これを行うことができる必要があります。
$ sed -r "s/\(([[:xdigit:]:]+)/('\1'/" file3
INSERT INTO radcheck(username, attribute, op, value) VALUES ('00:23:32:c2:a9:e8','Auth-Type',':=','Accept');
すべてのロケールの[:xdigit:]
すべての16進数と一致します。したがって、([[:xdigit:]:]+)
MACアドレス(16進数またはコロン)が一致します。
答え2
sed
グローバル規模で作業するときは、読む方法について考える必要があります。部分置換は、g
パターン空間をユーザーの仕様に従って区切られた個々のフィールドに分割し、各フィールドで機能します。区切り文字は、読み取る順序で左から右に認識され、sed
各操作はできるだけ早く適用されます。以下は、s///
目的の操作を実行する代替文です。
sed "s/\(([^)]*)[^,]*\)\{0,1\},\([^,)]*\)/\1,'\2'/g
" <<\IN
INSERT INTO radcheck(id, username, attribute, op, value) VALUES (,,00:23:32:c2:a9:e8,Auth-Type,:=,Accept);
実行時に以下を印刷します。
INSERT INTO radcheck(id, username, attribute, op, value) VALUES (,'','00:23:32:c2:a9:e8','Auth-Type',':=','Accept');
それだけです:
\(([^)]*)[^,]*\)\{0,1\}
*
- 最も重要なのは、0+一致と他の種類の分布です。ブロック全体はオプションです。sed
機会が与えられたら、その場所に空の文字列を一致させます。そして実際には何時間もそうします。それ以外の場合はまったく機能しません。しかし、\{0,1\}
使ったsed
結果いいえマッチもっとこのような全体のシーケンスより。だから流通が重要です。このブロックには次のものがあります。(
- 左括弧が少なくとも1つ必要です。[^)]*
- 0 +右以外の括弧。)
- 閉じ括弧[^,]*
- 0 + カンマではありません。
sed
\(
グループ化されているので、順番にそしてブロックでそれぞれ一致します\)
。 0+*
マッチは非常にグローバルに重要 -+
この設定で1つ以上を使用している場合徹底的にアプリケーション編集の効率を下げます。上記のブロックへの入力では、sed
文字列を次のように区切ります。INSERT INTO radcheck
- この文字列が続きます。今後私たちのすべての一致は含まれていません。無視されます。(id, username, attribute, op, value) VALUES (
- この文字列は、オプションの完全*
一致ブロックを構成します。最初にsed
一致し、次には(
thenの完全な文字列、そして最後に重要なのは私たちを含む完全な文字列です。[^)]*
)
[^,]*
超過のもう一つの一致事例です(
。今は一致できないため、(
このオプションの一致グループの次の項目をスキップします。sed
次のことを試してみましょう。
2番目のシーケンスにsed
置換を適用すると、\2
(.,.,.)
まだ\1
また、代替品を適用してください。それでも一致 \1
。私は初めて次\1
のように一致します。みんな (.,.,.)..(
ブロックして保存してから - 自分で\1
交換してください。\1
2番目のシーケンスの先頭から次のシーケンスが発生するまで、各一致(つまり、コンマが一致するたびに)は空の文字列 (
sed
に置き換えられます。\1
1行にそのようなシーケンスがたくさんあると仮定し、カンマが区切り(
)
文字内にのみ表示されると仮定すると、sed
各シーケンスに対して引用符が交互に表示されます。以下は、複数回使用した例です。
INSERT INTO radcheck(id, username, attribute, op, value) VALUES (,'','00:23:32:c2:a9:e8','Auth-Type',':=','Accept');INSERT INTO radcheck(id, username, attribute, op, value) VALUES (,'','00:23:32:c2:a9:e8','Auth-Type',':=','Accept');INSERT INTO radcheck(id, username, attribute, op, value) VALUES (,'','00:23:32:c2:a9:e8','Auth-Type',':=','Accept');
,\([^,)]*\)
- 唯一の注意いいえ完全正規表現のオプションの一致は,
カンマです。式と入力で他のブロックが前に表示されるため、sed
適用できます。ただし、他のすべての項目が同じ場合、コンマは優先順位を持ちます。これはsをどこにも挿入sed
しない唯一の理由です。''
他の2つはブロックの各バイト間で行われます。いいえsed
- 区切りが適用された場合は空の文字列と一致します。sed
notとnotのすべての文字シーケンスを引き続き一致させて\2
保存します。これは発生したすべてのカンマを置き換えます。埋めることができるポイントに到達するまで、このようにして継続し、そうなります。)
,
,'\2'
(
\1
答え3
この試み:
sed 's/,,/,\x27\x27,/'
\x27
16進エスケープコードです。'
デモ
$ echo 'INSERT INTO `radcheck`(`id`, `username`, `attribute`, `op`, `value`) VALUES (,,00:23:32:c2:a9:e8,Auth-Type,:=,Accept);' |
> sed 's/,,/,\x27\x27,/'
INSERT INTO `radcheck`(`id`, `username`, `attribute`, `op`, `value`) VALUES (,'',00:23:32:c2:a9:e8,Auth-Type,:=,Accept);