グラフィック以外の文字を含む1行のファイルがありますが、パターンに基づいて分割したいと思います。私のパターンは \[0-9][0-9][0-9]
;私は何をしますか?たとえば、次の行を分割したいとします。
\001abd \002pqr \003xyz
到着する:
\001abd
\002pqr
\003xyz
私は/bin/shをデフォルトのシェルとして使用します。
別の入力例:
CHANGE^\039^OE@ MORE^\040^L^[[00m^OAC DEPOSIT TO WHICH ACCOUNT^N020^^\055^L^[(1^[[00m^OAA PAYMENT FROM WHICH ACCOUNT^N020
希望の出力:
CHANGE^
\039^OE@ MORE^
\040^L^[[00m^OAC DEPOSIT TO WHICH ACCOUNT^N020^^
\055^L^[(1^[[00m^OAA PAYMENT FROM WHICH ACCOUNT^N020
1行のファイルサイズは80KBで、GNU sedバージョン4.2.1を使用しており、オペレーティングシステムはRed Hat Enterprise Linux Serverバージョン6.5(San Diego)です。
答え1
予備的な問題文があり、様々な解決策が提案されている。実際のデータが説明と一致しないため、これは機能しないことがわかりました。
考えられる答え
私のパターンは次のとおりです。
FS[0-9][0-9][0-9]
(FSは「フィールド区切り文字」です。)これをスクリプトでどのように使用できますかsed
?
BashとBSDの場合、sed
これを使用できます(これはジョン1024 提案済みBSDとMac OS Xを使ってsed
-E
拡張正規表現記号を有効にする):
sed -E $'s/(.)(\x1C[[:digit:]]{3})/\\1\\\n\\2/g' file1
記号$'…'
はBashです。ANSI C見積もり器具。 FSのバイト値は、28、16進数0x1C、または8進数038です。二重バックスラッシュについてはsed
バックスラッシュをご覧ください。\n
前の内容は、マニュアル(このセクション)の規定を\\
満たしています。sed
s///
改行を置き換えて行を分割できます。代替文字列に改行文字を指定するには、その前にバックスラッシュを追加します。
GNUで何が機能しているかを確認してくださいsed
。
また、FSが時々次のようにエンコードされることを観察しましたControl-Backslash(Control-Aコード1がありますが、Aコード65 = 64 + 1があり、バックスラッシュには\コード92 = 64 + 28があるため)。いつも学生質問に混乱があります。
GNUを参照してくださいsed
-r
BSDが実行する操作を実行するために使用されます-E
。sed
いかなる種類のシンボルも認識されません。
研究背景
ファイルをメールで送信しました。受け取った内容が正しい場合は、必要な内容の別の説明が必要です。
単語数出力:
$ wc file1
1 8804 80106 file1
$
16進ダンプの出力は次のとおりです。
$ odx file1 | sed 20q
0x0000: 33 1C 1C 1C 31 31 1C 30 30 31 0E 32 30 31 1C 30 3...11.001.201.0
0x0010: 30 32 0E 32 30 31 1C 30 30 33 0E 32 30 33 1C 30 02.201.003.203.0
0x0020: 30 34 24 20 1C 30 30 35 0E 30 30 32 1C 30 30 36 04$ .005.002.006
0x0030: 0E 30 30 32 1C 30 31 31 0C 1B 28 32 0F 45 40 20 .002.011..(2.E@
0x0040: 20 20 59 4F 55 52 20 43 41 52 44 20 49 53 20 4E YOUR CARD IS N
0x0050: 4F 54 20 20 53 45 52 56 49 43 45 44 0F 46 40 20 OT SERVICED.F@
0x0060: 20 20 20 20 20 20 20 20 20 42 59 20 20 54 48 49 BY THI
0x0070: 53 20 41 54 4D 20 0F 47 40 20 20 20 20 20 50 4C S ATM .G@ PL
0x0080: 45 41 53 45 20 54 41 4B 45 20 20 59 4F 55 52 20 EASE TAKE YOUR
0x0090: 43 41 52 44 1B 28 37 0F 49 40 20 20 20 20 20 20 CARD.(7.I@
0x00A0: 20 5C 26 20 2D 28 23 58 3E 3D 20 5C 25 22 40 22 \& -(#X>= \%"@"
0x00B0: 20 41 22 20 0F 4A 40 20 20 20 20 20 20 20 30 57 A" .J@ 0W
0x00C0: 5F 40 5B 3F 4A 58 20 2D 28 40 23 51 20 59 5F 22 _@[?JX -(@#Q Y_"
0x00D0: 20 0F 4B 40 20 20 30 3E 5F 40 22 3E 40 26 20 22 .K@ 0>_@">@& "
0x00E0: 40 20 3E 5B 3D 20 20 2D 28 40 23 51 20 23 4D 47 @ >[= -(@#Q #MG
0x00F0: 55 1B 28 32 1C 30 31 34 0C 1B 28 3E 0F 43 40 20 U.(2.014..(>.C@
0x0100: 20 20 45 53 50 2D 4C 49 4E 4B 2F 46 54 53 0F 45 ESP-LINK/FTS.E
0x0110: 40 20 20 20 20 20 20 20 41 54 4D 0F 47 40 20 4D @ ATM.G@ M
0x0120: 41 52 4B 45 54 49 4E 47 20 4D 45 53 53 41 47 45 ARKETING MESSAGE
0x0130: 20 45 32 1C 30 31 35 0C 1C 30 31 38 0C 1C 30 32 E2.015..018..02
$
以下は同じデータですod -c
。
$ od -c file1 | sed 20q
0000000 3 034 034 034 1 1 034 0 0 1 016 2 0 1 034 0
0000020 0 2 016 2 0 1 034 0 0 3 016 2 0 3 034 0
0000040 0 4 $ 034 0 0 5 016 0 0 2 034 0 0 6
0000060 016 0 0 2 034 0 1 1 \f 033 ( 2 017 E @
0000100 Y O U R C A R D I S N
0000120 O T S E R V I C E D 017 F @
0000140 B Y T H I
0000160 S A T M 017 G @ P L
0000200 E A S E T A K E Y O U R
0000220 C A R D 033 ( 7 017 I @
0000240 \ & - ( # X > = \ % " @ "
0000260 A " 017 J @ 0 W
0000300 _ @ [ ? J X - ( @ # Q Y _ "
0000320 017 K @ 0 > _ @ " > @ & "
0000340 @ > [ = - ( @ # Q # M G
0000360 U 033 ( 2 034 0 1 4 \f 033 ( > 017 C @
0000400 E S P - L I N K / F T S 017 E
0000420 @ A T M 017 G @ M
0000440 A R K E T I N G M E S S A G E
0000460 E 2 034 0 1 5 \f 034 0 1 8 \f 034 0 2
$
以下は、データの文字頻度分析です。
= 3: 1
= 10: 1
= 12: 648
= 14: 883
= 15: 3461
= 27: 1384
= 28: 722
= 32: 15248
! = 33: 178
" = 34: 1236
# = 35: 1847
$ = 36: 2
% = 37: 44
& = 38: 945
' = 39: 197
( = 40: 2096
) = 41: 1434
* = 42: 695
+ = 43: 25
, = 44: 446
- = 45: 1431
. = 46: 92
/ = 47: 29
0 = 48: 2453
1 = 49: 1279
2 = 50: 1052
3 = 51: 758
4 = 52: 427
5 = 53: 565
6 = 54: 299
7 = 55: 862
8 = 56: 414
9 = 57: 423
: = 58: 78
; = 59: 330
< = 60: 3
= = 61: 313
> = 62: 1683
? = 63: 60
@ = 64: 3472
A = 65: 2268
B = 66: 791
C = 67: 2034
D = 68: 1480
E = 69: 2862
F = 70: 732
G = 71: 692
H = 72: 799
I = 73: 1202
J = 74: 360
K = 75: 358
L = 76: 963
M = 77: 823
N = 78: 1483
O = 79: 1726
P = 80: 588
Q = 81: 507
R = 82: 1411
S = 83: 1624
T = 84: 1905
U = 85: 1172
V = 86: 151
W = 87: 372
X = 88: 1063
Y = 89: 647
Z = 90: 758
[ = 91: 1026
\ = 92: 665
] = 93: 275
^ = 94: 397
_ = 95: 1179
a = 97: 1
c = 99: 1
d = 100: 1
m = 109: 240
o = 111: 2
p = 112: 2
q = 113: 4
r = 114: 2
s = 115: 2
t = 116: 4
u = 117: 1
w = 119: 1
y = 121: 1
z = 122: 15
最後の列の数字の合計は80106と一致しますwc
。
ご覧のとおり、改行文字(コード10)は1つだけで、ファイルの末尾に表示されます。小文字は少なく、大文字は多く、バックスラッシュも適度ですが(今まで表示されたデータでは見えないもの)、バックスラッシュの後に数字はありません。 ASCII範囲外の文字コードはなく(上位ビットが設定されている文字コードはありません)、ASCII範囲の適用範囲は不完全です。
バックスラッシュの後にどの文字が出てくるのかを確認するために高速パーサーを作成しました。
#include <stdio.h>
int main(void)
{
int c;
int count[256] = { 0 };
while ((c = getchar()) != EOF)
{
if (c == '\\')
{
c = getchar();
count[c]++;
}
}
for (int i = 0; i < 255; i++)
{
if (count[i] != 0)
printf("%3d = %5d\n", i, count[i]);
}
return 0;
}
このファイルを実行すると、次のようになります。
12 = 3
14 = 58
15 = 3
27 = 25
34 = 10
35 = 51
37 = 14
38 = 126
40 = 9
44 = 51
45 = 26
47 = 2
59 = 17
62 = 118
64 = 46
65 = 2
66 = 2
67 = 17
69 = 1
71 = 4
72 = 5
74 = 15
79 = 1
81 = 9
83 = 1
85 = 5
88 = 18
90 = 12
91 = 6
95 = 8
数の合計は665で、元の文字分析のバックスラッシュ数と一致します。
数値コードは48..57です。バックスラッシュの後の文字は数字ではありません。
これが提示されたさまざまなソリューションが失敗した理由です。データが説明されたものと似ていなかったので、彼らは決して機会を得ませんでした。
答え2
sedを使用してください:
$ cat file
\001abd \002pqr \003xyz
$ sed -E 's/(.)(\\[[:digit:]]{3})/\1\n\2/g' file
\001abd
\002pqr
\003xyz
同じsedコマンドを使用しているがデータが異なる例:
$ cat file2
CHANGE^\039^OE@ MORE^\040^L^[[00m^OAC DEPOSIT TO WHICH ACCOUNT^N020^^\055^L^[(1^[[00m^OAA PAYMENT FROM WHICH ACCOUNT^N020
$ sed -E 's/(.)(\\[[:digit:]]{3})/\1\n\2/g' file2
CHANGE^
\039^OE@ MORE^
\040^L^[[00m^OAC DEPOSIT TO WHICH ACCOUNT^N020^^
\055^L^[(1^[[00m^OAA PAYMENT FROM WHICH ACCOUNT^N020
アップデート:FS-番号-番号-番号分割
ASCII「ファイル区切り文字」(FS)文字は16進数です1C
。 GNU sedの使用:
sed -E 's/(.)(\x1c[[:digit:]]{3})/\1\n\2/g'
これを実証するためにテストファイルを作成しましょう。
$ echo $'One\x1c123Two\x1c456Three\x1c7none' >newfile
それでは、以下を実行してみましょうsed
。
$ sed -E 's/(.)(\x1c[[:digit:]]{3})/\1\n\2/g' newfile
One
123Two
456Three7none
回線が正常に分割されました。
議論する
私の端末では、上記のようにFS文字は表示されません。あまり走らないと目立つようになります。たとえば、実行less newfile
結果は次のようになります。
One^\123Two^\456Three^\7none
ここでは、FS文字がで表示されることがわかります^\
。これは質問に示された第2の入力例と一致する。
CHANGE^\039^OE@ MORE^\040^L^[[00m^OAC DEPOSIT TO WHICH ACCOUNT^N020^^\055^L^[(1^[[00m^OAA PAYMENT FROM WHICH ACCOUNT^N020
答え3
次から始めたい場合:
\001abc \002jkl \003xyz
...到着...
\001abc
\002jkl
\003xyz
...最も簡単で効率的なソリューションは次のとおりです。
tr \ \\n <in >out
\n
ただし、これはスキーマに基づいて入力をewlineに分割することとは異なり、\[0-9][0-9][0-9]
次の影響を受ける可能性があります。
sed 's/\\[0-9]\{3\}/&\n/g' <in >out
...そして次に続くことができます...
\001
abc \002
jkl \003
xyz
\n
...おそらく改行文字を挿入したいという意味のようですが今後毎回表示される\[0-9][0-9][0-9]
場合は、次のようにできます。
sed 's/\\[0-9]\{3\}/\n&/g' <in >out
...得るために...
\001abc \002jkl \003xyz
...各行の末尾にスペースがあります。
ただし、どちらの方法も非常に長い入力ラインを処理するときに問題がある可能性があります。入力ファイル全体に1行しかない場合は、次のことを確実に実行できます。
{ tr '\\' \\n |
sed -e:t \
-e'$!N;/\n[0-9]\{3\}/!s/\n/\\/;tt' \
-e's/\n/&\\/;P;D'
} <infile >outfile
上記のコマンドチェーンtr
が解析されます。みんな入力のバックスラッシュは改行\n
文字であり、結果は結果としてパイプされ、各入力行の最初の3桁をsed
再帰的に推定します。長い入力行の処理にはまったく問題がなく、操作が完了したら、出力に少なくとも必要な数のewline文字を含める必要があります。 ewline 文字が次のような場合t
tr
\n
\n
いいえその後には3桁の数字が続き、単にバックスラッシュに置き換えられます。そうでない場合はい\n
次に、改行文字と3桁の数字の間にバックスラッシュを挿入します。
2番目の例の結果は次のとおりです。
CHANGE^
\039^OE@ MORE^
\040^L^[[00m^OAC DEPOSIT TO WHICH ACCOUNT^N020^^
\055^L^[(1^[[00m^OAA PAYMENT FROM WHICH ACCOUNT^N020