回答:
以下にいくつかのアプローチを示します。私はブレース展開(file{1..4}.txt
)を使用していますfile1.txt file2.txt file3.txt file4.txt
Perl
perl -i -pe 's/.*/ Good Morning / if $.==5' file{1..4}.txt
-i
:perl
ファイルをその場で編集し、元のファイルを変更します。
-i
後にファイル拡張子のサフィックスが付いている場合、変更されたすべてのファイルに対してバックアップが作成されます。例:-i.bak
作成しfile1.txt.bak
た場合file1.txt
、実行中に変更されます。
-p
:入力ファイルを1行ずつ読み取り、スクリプトを適用して印刷することを意味します。
-e
:コマンドラインからスクリプトを渡すことができます。
s/.*/ Good Morning /
:これにより、現在の行のテキスト(.*
)がGood Morningに置き換えられます。
$.
入力ファイルの現在の行番号を保持する特別なPerl変数です。したがって、s/foo/bar/ if $.==5
は、5行目のみで置換することfoo
を意味しbar
ます。
sed
sed -i '5s/.*/ Good Morning /' file{1..4}.txt
-i
:のようにperl
、ファイルをその場で編集します。デフォルトでsed
は、入力ファイルの各行を印刷します。5s/pattern/replacement/
第5行に置換した代替パターンを意味します。
Awk
for f in file{1..4}.txt; do
awk 'NR==5{$0=" Good Morning "}1;' "$f" > foobar && mv foobar "$f";
done
awk
-i
オプションに相当するものはありません¹。これは、一時ファイル(foobar
)を作成してから、元のファイルを上書きするように名前を変更する必要があることを意味します。bashループfor f in file{1..4}.txt; do ... ; done
はそれぞれを単に通過しfile{1..4}.txt
、現在のファイル名をとして保存します$f
。ではawk
、NR
現在の行番号であり、現在の行$0
の内容です。そのため、スクリプトは$0
5行目のみで行()を「Good Morning」に置き換えます。1;
であるawk
「行を印刷する」ため。
coreutils
for f in file{1..4}.txt; do
(head -4 "$f"; echo " Good Morning "; tail -n +6 "$f") > foobar &&
mv foobar "$f";
done
ループについては、前のセクションで説明しています。
head -4
:最初の4行を印刷します
echo " Good Morning "
:印刷「おはよう」
tail -n +6
:6行目からファイルの最後まですべてを印刷します
( )
これらの3つのコマンドを括弧で囲むと、3つすべての出力(つまり、最初の4行、「おはよう」、残りの行)をキャプチャして、ファイルにリダイレクトできます。
以下を使用できますsed
。
sed '5s/^/Good morning /' file
Good morning
ファイルの5行目に追加します。
代わりに5行目の内容を置き換える場合は、次のように言います。
sed '5s/.*/Good morning/' file
ファイルへの変更をインプレースで保存する場合は、次の-i
オプションを使用します。
sed -i '5s/.*/Good morning/' file
sed
一度に複数のファイルを処理できます。コマンドの最後にファイル名を追加するだけです。また、bash展開を使用して特定のファイルに一致させることもできます。
# manually specified
sed -i '5s/.*/Good morning/' file1.txt file2.txt file3.txt file4.txt
# wildcard: all files on the desktop
sed -i '5s/.*/Good morning/' ~/Desktop/*
# brace expansion: file1.txt, file2.txt, file3.txt, file4.txt
sed -i '5s/.*/Good morning/' file{1..4}.txt
あなたはここにブレース展開についての詳細を読むことができます。
GNU awkバージョン4.1.0以降には、インプレース編集を可能にする拡張機能が付属しています。だからあなたは言うことができます:
gawk -i inplace 'NR==5{$0="Good morning"}7' file
ファイルの5行目をGood morning
!
私はPythonのソリューションを見なかったので、ここにあります:
import sys
import os
def open_and_replace(filename):
with open(filename) as read_file:
temp = open("/tmp/temp.txt","w")
for index,line in enumerate(read_file,1):
if index == 5:
temp.write("NEW STRING\n")
else:
temp.write(line.strip() + "\n")
temp.close()
os.rename("/tmp/temp.txt",filename)
for file_name in sys.argv[1:]:
open_and_replace(file_name)
基本的な考え方は、引数としてコマンドラインで提供される各ファイルについて、一時ファイルを書き出し、元のファイルの各行を列挙することです。行のインデックスが5の場合、異なる行を書き出します。残りは、古いファイルを一時ファイルのデモに置き換えるだけです:
$> ls
file1.txt file2.txt file3.txt
$> cat file1.txt
line 1
line 2
line 3
line 4
GOOD MORNING
line 6
$> python ~/replace_5th_line.py file1.txt file2.txt file3.txt
$> cat file1.txt
line 1
line 2
line 3
line 4
NEW STRING
line 6
$> cat file2.txt
line 1
line 2
line 3
line 4
NEW STRING
line 6
リスト内包表記でも同じことが実現できます。以下は、同じスクリプトの1行です。
cat /etc/passwd | python -c 'import sys; print "\n".join(["CUSTOM" if index == 5 else line.strip() for index,line in enumerate(sys.stdin,1)])'
またはなし cat
python -c 'import sys; print "\n".join(["CUSTOM" if index == 5 else line.strip() for index,line in enumerate(sys.stdin,1)])' < /etc/passwd
残っているのは、編集したコンテンツの出力を別のファイルに単純にリダイレクトすることです > output.txt
以下は、この回答で提案されているperlプロセスをまとめるbashスクリプトです。
/ tmp / it
console:
enabled:false
次に、次を実行します。
$ search_and_replace_on_line_of_file.sh false true 2 /tmp/it
ファイルには次が含まれます
/ tmp / it
console:
enabled:true
function show_help()
{
IT=$(CAT <<EOF
usage: SEARCH REPLACE LINE_NUM FILE
e.g.
false true 52 /tmp/it -> replaces false with true on line 52 of file /tmp/it
)
echo "$IT"
exit
}
if [ "$1" == "help" ]
then
show_help
fi
if [ -z "$4" ]
then
show_help
fi
SEARCH_FOR=$1
REPLACE_WITH=$2
LINE_NO=$3
FILE_NAME=$4
perl -i -pe "s/$SEARCH_FOR/$REPLACE_WITH/ if $.==$LINE_NO" $FILE_NAME