bash
変数のファイルパスを使用してスクリプトから複数行のファイルを読み込み、複数文字の区切り文字を使用して並列化を一致させ、結果を別の変数に保存したいと思います。
空行と末尾の新しい行をスキップし、末尾の区切り文字は必要ありません。
\r\n
また、追加の「費用」がなければ改行でもサポートしない理由をサポートしたいと思います\r
(もちろん\n
)。
スクリプトは、GNUのbash 4.2.46、sed 4.2.2、awk 4.0.2、grep 2.20、coreutils 8.22(tr、cat、Paste、sort、cut、head、tail、tee ...)を使用してRHELで実行されます。する必要があります。 xargs 4.5.11とlibc 2.17、Perl 5.16.3、Python 2.7.5、openjdk 11.0.8。
1 日に 2 回程度 ca ファイルで実行する必要があります。まともなマシン/仮想マシンに10本のラインがあります。読みやすさ、メンテナンスの容易さ、シンプルさが大幅に低下しない場合は、より高いパフォーマンスのソリューションを喜んで受け入れます。
Win7
読み取るファイルは、同じコンピュータまたは別のシステムで作成および変更できますWin10
。
これまでの私のアプローチは
joined_string_var=$(sed 's/\r/\n/g' $filepathvar | grep . | sed ':a; N; $!ba; s/\n/; /g')
だから最初にすべての改行形式を上書き
\r
し、\n
出力をgrepから読み取ることができるように変更しました。その後、空行を削除します。
grep .
最後に、sedを使用して実際の行マージを実行しました。
catの使用を避けるために最初のステップではnotを使用しましたがsed
、これを好むかどうかわかりません。tr
joined_string_var=$(cat $filepathvar | tr '\r' '\n' | grep . | sed ':a; N; $!ba; s/\n/; /g')
修正する:どういうわけか簡単なリダイレクトを完全に逃しました。
joined_string_var=$(tr '\r' '\n' <$filepathvar | grep . | sed ':a; N; $!ba; s/\n/; /g')
これをよりエレガントに行う方法についてのアイデアはありますか(コマンド数が少なく、パフォーマンスが向上し、簡潔さと読みやすさも低下しません)。
答え1
優雅さは正しい正規表現から来ることができます。すべての行終端文字を目的の区切り文字\r
(\n
)に変更する代わりに(GNU sedではこれを理解するsed実装はほとんどありませんが、すべてのsed実装が理解しているわけではありません):s/\r/\n/g
\r\n
\r
\n
\r
-E
sed -E 's/\r\n|\r|\n/; /g'
または空白行を削除するには走るこれらの行終端は次のとおりです。
sed -E 's/[\r\n]+/; /g'
パターン空間ですべてのラインターミネータをキャプチャできる場合は機能します。これは、ファイル全体を編集できるようにメモリに保存することを意味します。
したがって、より簡単な方法を使用できます(GNU sedの1つのコマンド)。
sed -zE 's/[\r\n]+/; /g; s/; $/\n/' "$filepathvar"
-z
ヌルバイトを行終端として使用して、\r
パターン空間のすべての合計を効果的に取得します。\n
すべての種類の行区切り文字をs/[\r\n]+/; /g
目的の文字列に変換します。
(最後)末尾の区切り文字を s/; $/\n/
実際の改行文字に変換します。
ノート
sedオプションは、-z
ゼロ区切り文字(0x00)を使用することを意味します。この区切り文字は、findがxargs()オプションと一致する改行-print0
()でファイル名を処理できる必要があるために使用されます。-0
これは、一部のツールがゼロで区切られた文字列を処理するように変更されたことを意味します。
これは、改行の代わりに0からファイルを分割する非posixオプションです。
Posixテキストファイルには0(NIL)バイトを含めないでください。このオプションを使用すると、処理する前にファイル全体をメモリにキャプチャすることを意味します。
NILからファイルを削除すると、sedのパターンスペースで改行文字を編集できます。ファイルにNILバイトがある場合、ファイル内のすべてのブロックで編集を続けることができるため、改行のアイデアはまだ有効です。
この-z
オプションはGNU sedに追加されました。 ATT sed(posixベース)にはそのようなオプションがなく(まだありません)、一部のBSD sedもまだありません。
このオプションの代替案は、-z
ファイル全体をメモリにキャプチャすることです。これは次の方法で行うことができます。
sed 'H;1h;$!d' # capture whole file in hold space.
sed ':a;N;$!ba' # capture whole file in pattern space.
パターンスペースにすべての改行(最後の行を除く)を配置すると編集可能になります。
sed -Ee 'H;1h;$!d;x' -e 's/(\r\n|\r|\n)/; /g
また、古いsedにはより長くより明示的なsedを使用する必要があり(\r\n|\r|\n)+
ます。[\r\n]+
\r
\n
[]
ラインガイド
一度に 1 行ずつ実行するソリューション ( \r
a は、このソリューションで有効な行終端者でもある)。これは、GNU awk を使用してファイル全体をメモリに保持する必要がないことを意味します(使用されるメモリが少ない)。
awk -vRS='[\r\n]+' 'NR>1{printf "; "}{printf $0}END{print ""}' file
正規表現レコード区切り文字のため、GNU awkでなければなりません[\r\n]+
。他のawkでは、レコード区切り文字はシングルバイトでなければなりません。
答え2
Sedを使用すると、perl
改行を使用する方が複雑ですが、Perlはそれを簡単に処理できます。
printf 'aa\nbb\ncc\n' > file
printf 'aa2\r\nbb2\r\ncc2\r\n' > file2
printf 'aa3\rbb3\rcc3\r' > file3
したがって、行の終わりがfile
あり、そこにあります(ところで、今はもはや使用されておらず、サポートするにはあまり意味がありません)。これで文字列にリンクします。\n
file2
\r\n
file3
\r
$ joined_string_var=$(perl -pe 's/(\r\n|\r|\n)/; /g' file file2 file3)
$ echo "$joined_string_var"
aa; bb; cc; aa2; bb2; cc2; aa3; bb3; cc3;
ただし、末尾の;
区切り文字を削除するには、2番目のパスが必要です。
$ joined_string_var=$(perl -pe 's/(\r\n|\r|\n)/; /g' file file2 file3 | sed 's/; $//')
$ echo "$joined_string_var"
aa; bb; cc; aa2; bb2; cc2; aa3; bb3; cc3
またはPerlから削除します。
$ joined_string_var=$(perl -ne 's/(\r\n|\r|\n)/; /g; $k.=$_; END{$k=~s/; $//; print $k}' file file2 file3)
$ echo "$joined_string_var"
aa; bb; cc; aa2; bb2; cc2; aa3; bb3; cc3
答え3
記録のためにzsh
(同様の要件があるが制限がない場合bash
)、次のことを行う必要があります。
IFS=$'\r\n'
joined=${(j[; ])$(<$filepathvar):#}
IFS=$'\r\n'
単語分割フィールド区切り文字をCRまたはLF文字に設定します(ksh93スタイルの$'...'
引用符を使用)。$(<file)
:単語噴射の影響を受けてksh
内容のように拡張されます(末尾改行なし)。file
${list:#pattern}
一致しないリストの要素pattern
(およびksh
s拡張子${list#pattern}
)に展開されます。ここでは、空行を削除するためのパターンとして空の文字列が使用されます。${(j[; ])list}
j
oinsリストの要素"; "
。
答え4
f=file
python3 -c "import re
print(re.sub(r'[\r\n]+', '; ', open('$f').read().strip('\r').strip('\n')))"
perl -nF'[\r\n]+' -0777E '$,="; ";
say @F;
' file