複数のテキストファイルの5行目の文字列を置き換える方法は?


22

単一のターミナルコマンドを使用して、複数のテキストファイルの5行目(file1.txt、file2.txt、file3.txt、file4.txt)を文字列「Good Morning」に置き換えたいと思います。

すべてのテキストファイルはにあります~/Desktop

注:私のデスクトップは6つの.txtファイルで構成されています。上記の4つのテキストファイルのみに変更を適用したいです。

回答:


40

以下にいくつかのアプローチを示します。私はブレース展開file{1..4}.txt)を使用していますfile1.txt file2.txt file3.txt file4.txt

  1. Perl

    perl -i -pe 's/.*/ Good Morning / if $.==5' file{1..4}.txt

    説明:

    • -iperlファイルをその場で編集し、元のファイルを変更します。

      -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ます。

  2. sed

    sed -i '5s/.*/ Good Morning /' file{1..4}.txt

    説明:

    • -i:のようにperl、ファイルをその場で編集します。

    デフォルトでsedは、入力ファイルの各行を印刷します。5s/pattern/replacement/第5行に置換した代替パターンを意味します。

  3. 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。ではawkNR現在の行番号であり、現在の行$0の内容です。そのため、スクリプトは$05行目のみで行()を「Good Morning」に置き換えます。1;であるawk「行を印刷する」ため。

    ¹ 新しいバージョンは、devnullが答えで示したとおりです。

  4. 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行、「おはよう」、残りの行)をキャプチャして、ファイルにリダイレクトできます。


23

以下を使用できます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


2

私は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


1

ExモードでVimを使用できます。

for b in 1 2 3 4
do
  ex -sc '5c|Good Morning' -cx file"$b".txt
done
  1. 5 5行目を選択

  2. c テキストを置き換える

  3. x 変更が行われた場合(書き込みがあった場合)に書き込み、終了する


0

以下は、この回答で提案されいる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

search_and_replace_on_line_of_file.sh

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 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.