私のディレクトリに次の内容のファイルがたくさんあるとしましょう*.txt
。texts
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Aliquam tincidunt mauris eu risus.
Vestibulum auctor dapibus neque.
私はそれを次に変えたい再帰的。
Vestibulum commodo felis quis tortor.
Ut aliquam sollicitudin leo.
Cras iaculis ultricies nulla.
Donec quis dui at dolor tempor interdum.
これはかなり大きな交換だからです。 1つずつ入力するには時間がかかる場合があります。
だからそんなオプションがあればもっといいと思います。
コピーして貼り付ける元のテキストをファイルに配置し、必要original.txt
な代替コンテンツを別のファイルに配置しますupdate.txt
。
その後、コマンドを実行してディレクトリ内のコンテンツで構成されている*.txt
すべてのファイルを見つけてそのコンテンツに置き換えます。texts
original.txt
update.txt
次の簡単な交換のようなものです。
find texts -name "*.txt" -exec sed -i 's/original/update/g' {} \;
これにより、手動で入力するのと同じエラーが発生せず、時間もかかりません。
しかし、これを達成するためにどのコマンドを使うべきかわかりません。可能ですか?
しかし、最初に元のテキストの可用性と出現回数を確認できる必要がありました。
次の簡単な検査のようになります。
cd texts
grep -r --color=always "original" | wc -l
ありがとうございます。
答え1
私はsed(またはawk)の代わりにPerlを使います。
find texts/ -name '*.txt' \
-exec perl -0777 -p -i.bak -e '
BEGIN {
$search = q{Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Aliquam tincidunt mauris eu risus.
Vestibulum auctor dapibus neque};
$replace = q{Vestibulum commodo felis quis tortor.
Ut aliquam sollicitudin leo.
Cras iaculis ultricies nulla.
Donec quis dui at dolor tempor interdum.};
};
s/\Q$search\E/$replace/mg' {} +
-0777
Perlに、ファイル全体を一度に「フルルック音を出し」、1つの長い文字列として処理するように指示します。-p
Perlが同様に動作するようにしますsed
(そしてその-n
オプションを使用すると同様に動作しますsed -n
)。-i.bak
ファイルを「所定の位置に」編集して、元の.bak
ファイルを拡張子として保存します。繰り返しますがsed -i
。バックアップコピーが必要ない場合は、
-i
代わりにjustを使用してください-i.bak
。\Q
Perl正規表現は、正規表現特殊文字が含まれていても、次のパターン(aが表示されるまで\E
)をリテラル文字列として扱うようにPerlに指示します。から
man perlre
:\Q
まで引用(無効)パターンメタ文字\E
\E
最終ケースの修正または参照セクションq{}
q
一重引用符とまったく同じPerl引用演算子を使用してください。これは、Perlスクリプトが一重引用符で囲まれた1行のコードで特に便利です(ここでバックスラッシュでエスケープできません。一重引用符内のエスケープコードは無視されるためです。man perlop
「参照とクラス参照演算子」を確認して検索してください。また参照してくださいperldoc -f q
(perldoc -f qq
二重引用符演算子と比較)。
ところで、単一のファイルでファイルのperl部分をテストし、出力を確認して、私が望むように動作することを確認することをお勧めします(つまり、findなし、特に何もありません-i.bak
)。
答え2
Debian 11 で実行される 1 つの方法は次のとおりです。
- バッシュ v.5.1.4(1)
- tr(GNU Coreutils) v.8.32
- sed(GNU sed) v.4.7
このスクリプトは次のように書かれています。
- 問題の各ファイルに
.txt
拡張子があるとします。 .txt
-filesと同じディレクトリで実行する必要があります。- 処理中に各ファイルの名前と内容を表示します。
- エラーが発生しても元のファイルを引き続き使用できるようにするには、ファイルを所定の位置に置き換えるのではなく、新しいファイルを作成してください。たとえば、代替テキストを変更する必要がある場合は、元のファイルに影響を与えることなく、単一のコマンドで新しく作成されたファイルを削除できます。
ディレクトリの内容:
pg1@TREX:~/foo$ ls
repla.sh text1.txt text2.txt
テキストファイルの内容:
pg1@TREX:~/foo$ for i in {1..2}; do cat text$i.txt; echo; done
This is the beginning
of the first text.
These lines
will be replaced.
This is the ending
of the first text.
This is the beginning
of the second text.
These lines
will be replaced.
This is the ending
of the second text.
テキストを置き換える:
New lines
that will replace
old lines.
交換.sh:
#!/bin/sh
for i in *.txt; do
echo $i
cat text.txt | tr '\n' '\r' | sed -e 's/These lines\rwill be replaced./New lines\rthat will replace\rold lines./g' | tr '\r' '\n' | tee $i.new
done
結果:
pg1@TREX:~/foo$ ./repla.sh
text1.txt
This is the beginning
of the first text.
New lines
that will replace
old lines.
This is the ending
of the first text.
text2.txt
This is the beginning
of the second text.
New lines
that will replace
old lines.
This is the ending
of the second text.
pg1@TREX:~/foo$ ls
repla.sh text1.txt text1.txt.new text2.txt text2.txt.new
必要に応じてスクリプトを調整する必要があります。たとえば、変更する必要がある拡張子が異なる(または拡張子のない)テキストファイルもある場合、またはファイルが別のディレクトリにある場合はそれに対応する必要があります。コメントアウトすると、echo $i
処理中にファイル名が表示されず、リダイレクト| tee
に置き換えると>
ファイルの内容が表示されません。内部置換のためには、新しいファイルを作成する必要があります。このファイルは、mv
元のファイルを置き換えるためにスクリプトに追加するだけです。
以下のEd Mortonのコメントを参照してください。
よりエレガントで長い段落に適した他の解決策があります。例えばこのスタックオーバーフローの質問前の段落と代替段落は変数にあります。