UPDATE(質問の終わりを参照)
私が見たテキスト「検索と置換」ユーティリティプログラムは、行単位でのみ検索するようです...
command-lineツールはありますかlocate1行のブロック(テキストファイル内)、およびreplace別の行ブロックで置き換えます。
例:テストファイルファイルに次の行が含まれていますかexact group
:
'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe:
All mimsy were the borogoves,
And the mome raths outgrabe.
'Beware the Jabberwock, my son!
The jaws that bite, the claws that catch!
Beware the Jubjub bird, and shun
The frumious Bandersnatch!'
ファイル内の複数行のテキストを置き換え、間違った行を上書きしていないことを確認できるように、これが必要です。
「The Jabberwocky」(ルイス・キャロル)を置き換えることはありませんが、斬新な例になります:)
UPDATE:
..(sub-update)sedを使用しない理由whenについての私の以下のコメントはonlyのコンテキストで;設計意図を超えてツールをプッシュしすぎないでください(私はsedを頻繁に使用しており、非常に貴重であると考えています)。
sedについての興味深いWebページと、それを使用しない場合を見つけました。
したがって、sedのすべての回答のため、リンクを投稿します。これは sedの一部ですFAQ sourceforgeで
また、何らかの方法があると確信していますdiff
は、テキストのブロックを見つけることができます(一度見つかったら、置換は非常にまっすぐです前方; head
およびtail
を使用)... 'diff'はすべての必要なデータをダンプしますが、それをフィルタリングする方法をまだ試していません...(まだ作業中です)
次の単純なpythonスクリプトでタスクを実行する必要があります。
#!/usr/bin/env python
# Syntax: multiline-replace.py input.txt search.txt replacement.txt
import sys
inp = open(sys.argv[1]).read()
needle = open(sys.argv[2]).read()
replacement = open(sys.argv[3]).read()
sys.stdout.write(inp.replace(needle,replacement))
他のほとんどのソリューションと同様に、ファイル全体が一度にメモリに丸thatみされるという欠点があります。ただし、小さなテキストファイルの場合は、十分に機能するはずです。
次のスニペットは、改行をパイプと交換し、置換を実行して、セパレーターを元に戻します。ユーティリティは、ラインが極端に長い場合、停止する可能性があります。検索文字列にない限り、交換する任意の文字を選択できます。
<old.txt tr '\n' '|' |
sed 's/\(|\|^\)'\''Twas … toves|Did … Bandersnatch!'\''|/new line 1|new line 2|/g' |
tr '|' '\n' >new.txt
AwkとPerlは、レコードセパレーターとして2つ以上の空白行の設定をサポートしています。 awkを使用して、-vRS=
(空のRS
変数)を渡します。 Perlでは、-000
(「段落モード」)を渡すか、$,=""
を設定します。ただし、複数段落の検索文字列があるため、ここでは役に立ちません。
AwkとPerlは、レコード区切り文字として任意の文字列を設定することもサポートしています。 RS
または$,
を検索文字列にない任意の文字列に設定します。
<old.txt Perl -pe '
BEGIN {$, = "|"}
s/^'\''Twas … toves\nDid … Bandersnatch!'\''$/new line 1\nnew line 2/mg
' >new.txt
一部のユーティリティでは、ファイル全体を簡単にメモリに読み込んで作業できます。
<old.txt Perl -0777 -pe '
s/^'\''Twas … toves\nDid … Bandersnatch!'\''$/new line 1\nnew line 2/mg
' >new.txt
行を1つずつ読んでください。空のバッファーから始めます。 「 'Twas」行が表示され、バッファーが空の場合は、バッファーに入れます。 「Dy gyre」が表示され、バッファーに1行ある場合は、現在の行をバッファーに追加します。 「Bandersnatch line」を追加したばかりの場合は、置換テキストを出力します。現在の行がバッファに入っていない場合は、バッファの内容を印刷し、現在の行を印刷してバッファを空にします。
psusi はsed実装を示します。 sedでは、バッファーの概念が組み込まれています。ホールドスペースと呼ばれます。 awkまたはPerlでは、変数を使用するだけです(おそらく2つ、1つはバッファーの内容用、もう1つは行数用)。
UPDATE:loevborgのpythonスクリプトは確かに最もシンプルで最適なソリューションです(それについては間違いありません)。それに満足していますが、(質問の最後に)提示したbashスクリプトは見た目ほど複雑ではないことを指摘したいと思います。それをテストするために使用したデバッグドロスをすべて削除しました。 。そしてここでも、このページを訪れる人のために、重荷はありません。これは、基本的にsed
ワンライナーであり、前と後の16進変換があります:
F=("$haystack" "$needle" "$replacement")
for f in "${F[@]}" ; do cat "$f" | hexdump -v -e '1/1 "%02x"' > "$f.hex" ; done
sed -i "s/$(cat "${F[1])}.hex")/$(cat "${F[2])}.hex")/p" "${F[0])}.hex"
cat "${F[0])}.hex" | xxd -r -p > "${F[0])}"
# delete the temp *.hex files.
帽子を指輪に投げ込むために、special正規表現文字で問題が発生しない「sed」ソリューションを考え出しました、1つでも使用しないためです! ..代わりに、ファイルのHexdumpedバージョンで動作します...
私はそれがあまりにも「重い」と思いますが、機能し、明らかにサイズ制限によって制限されていません。GNU sedには無制限のパターンがありますバッファサイズ。これは、検索行の16進ダンプブロックが終わる場所です。したがって、その点で大丈夫です...
私はまだdiff
ソリューションを探しています、なぜならそれは空白に関してより柔軟であるからです(そして私は期待するでしょう;より速い)...しかしまでそれから..それは有名なセッド氏です。 :)
このスクリプトはそのまま完全に実行されており、合理的にコメントされています...
より大きく見えます。必要なコードは7行のみです。
半現実的なテストのために、 Project Gutenberg (363.1 KB)...から本「鏡を通して見るアリス」をダウンロードし、元のJabberwockyの詩を行に置き換えます-それ自体の逆バージョン..(興味深いことに、逆方向に読むとそれほど違いはありません:)
PS。このメソッドの弱点は、元のファイルが改行として\ r\n(0xODOA)を使用し、「一致するテキスト」が\ n(0x0A)で保存される場合です。水...(「diff」にはそのような問題はありません)...
# In a text file, replace one block of lines with another block
#
# Keeping with the 'Jabberwocky' theme,
# and using 'sed' with 'hexdump', so
# there is no possible *special* char clash.
#
# The current setup will replace only the first instance.
# Using sed's 'g' command, it cah change all instances.
#
lookinglass="$HOME/Through the Looking-Glass by Lewis Carroll"
jabberwocky="$lookinglass (jabberwocky)"
ykcowrebbaj="$lookinglass (ykcowrebbaj)"
##### This section if FOR TEST PREPARATION ONLY
fromURL="http://www.gutenberg.org/ebooks/12.txt.utf8"
wget $fromURL -O "$lookinglass"
if (($?==0))
then echo "Download OK"
else exit 1
fi
# Make a backup of the original (while testing)
cp "$lookinglass" "$lookinglass(fromURL)"
#
# Extact the poem and write it to a file. (It runs from line 322-359)
sed -n 322,359p "$lookinglass" > "$jabberwocky"
cat "$jabberwocky"; read -p "This is the original.. (press Enter to continue)"
#
# Make a file containing a replacement block of lines
tac "$jabberwocky" > "$ykcowrebbaj"
cat "$ykcowrebbaj"; read -p "This is the REPLACEMENT.. (press Enter to continue)"
##### End TEST PREPARATION
# The main process
#
# Make 'hexdump' versions of the 3 files... source, expected, replacement
cat "$lookinglass" | hexdump -v -e '1/1 "%02x"' > "$lookinglass.xdig"
cat "$jabberwocky" | hexdump -v -e '1/1 "%02x"' > "$jabberwocky.xdig"
cat "$ykcowrebbaj" | hexdump -v -e '1/1 "%02x"' > "$ykcowrebbaj.xdig"
# Now use 'sed' in a safe (no special chrs) way.
# Note, all files are now each, a single line ('\n' is now '0A')
sed -i "s/$(cat "$jabberwocky.xdig")/$(cat "$ykcowrebbaj.xdig")/p" "$lookinglass.xdig"
##### This section if FOR CHECKING THE RESULTS ONLY
# Check result 1
read -p "About to test for the presence of 'jabberwocky.xdig' within itself (Enter) "
sed -n "/$(cat "$jabberwocky.xdig")/p" "$jabberwocky.xdig"
echo -e "\n\nA dump above this line, means: 'jabberwocky' is as expected\n"
# Check result 2
read -p "About to test for the presence of 'ykcowrebbaj.xdig' within itself (Enter) "
sed -n "/$(cat "$ykcowrebbaj.xdig")/p" "$ykcowrebbaj.xdig"
echo -e "\n\nA dump above this line, means: 'ykcowrebbaj' is as expected\n"
# Check result 3
read -p "About to test for the presence of 'lookinglass.xdig' within itself (Enter) "
sed -n "/$(cat "$ykcowrebbaj.xdig")/p" "$lookinglass.xdig"
echo -e "\n\nA dump above this line, means: 'lookinglass' is as expected\n"
# Check result 4
read -p "About to test for the presence of 'lookinglass.xdig' within itself (Enter) "
sed -n "/$(cat "$jabberwocky.xdig")/p" "$lookinglass.xdig"
echo -e "\n\nNo dump above this line means: 'lookinglass' is as expected\n"
##### End of CHECKING THE RESULTS
# Now convert the hexdump to binary, and overwrite the original
cat "$lookinglass.xdig" | xxd -r -p > "$lookinglass"
# Echo the "modified" poem to the screen
sed -n 322,359p "$lookinglass"
echo -e "\n\nYou are now looking at the REPLACEMENT text (dumped directly from the source 'book'"
私はsedでこれを行う方法がなければならないと確信していました。いくつかのグーグルの後に、私はこれに出くわしました:
http://austinmatzko.com/2008/04/26/sed-multi-line-search-and-replace/
それに基づいて、私は書いてしまいました:
sed -n '1h;1!H;${;g;s/foo\nbar/jar\nhead/g;p;}' < x
Xの内容を正しく取りました:
フーバー
そして吐き出します:
ジャーヘッド
あなたが白髪sed
とPerl
を嫌うとしても、灰色のテンプルawk
に好みがあるかもしれません。 この答え はあなたが探しているもののようです。ここで再現します。 3つのファイルがあり、needle
のreplacement
をhaystack
に置き換えたいとします。
awk ' BEGIN { RS="" }
FILENAME==ARGV[1] { s=$0 }
FILENAME==ARGV[2] { r=$0 }
FILENAME==ARGV[3] { sub(s,r) ; print }
' needle replacement haystack > output
これは正規表現を含まず、改行文字をサポートします。かなり大きなファイルで動作するようです。ファイル全体をメモリに丸involveみする必要があるため、任意のサイズのファイルでは機能しません。よりエレガントにしたい場合は、bashスクリプトでShebang全体を囲むか、awk
スクリプトに変換できます。