テキストファイルの行全体を行番号で置き換える方法


152

bashスクリプトでファイルの行全体を置き換えたい状況があります。行番号は常に同じであるため、ハードコードされた変数になる可能性があります。

その行の一部の文字列を置き換えようとしているのではなく、その行全体を新しい行に置き換えたいだけです。

これを行うためのbashメソッド(または.shスクリプトにスローできる単純なもの)はありますか?

回答:


228

最大ではありませんが、これはうまくいくはずです:

sed -i 'Ns/.*/replacement-line/' file.txt

where Nは、ターゲットの行番号に置き換える必要があります。これにより、元のファイルの行が置き換えられます。変更したテキストを別のファイルに保存するには、-iオプションをドロップします。

sed 'Ns/.*/replacement-line/' file.txt > new_file.txt

1
画面にダンプするのではなく、問題のファイルをsedに変更させる方法はありますか?
user788171 2012年

8
私にとってそれは言う:sed: -e expression #1, char 26: unknown option to ``s'そして私の行は:sed -i '7s/.*/<param-value>http://localhost:8080/ASDF/services/REWS.REWSHttpSoap12Endpoint/</param-value>/' $TCE_SVN_HOME\trunk\tce\EWC\WebContent\WEB-INF\web.xmlです。何か案が?
Danijel 2013

4
/置換テキストのそれぞれは、sエスケープ(\/)されていない限り、コマンドの終了スラッシュとして解釈されます。ただし、最も簡単な方法は、使用されていない別の文字を区切り文字として選択することです。たとえば、sed -i '7s{.*}{<param-value>http://...}' $TCE_SVN_HOME/trunk...
chepner 2013

4
その説明は少し混乱し、うまくいかないようです。あなたたちはsedは、その区切り文字の設定機能に問題がある場合、あなたはこれを見てしたいことがあります。grymoire.com/Unix/Sed.html#uh-2それは背後にある最初の文字は言うs。区切り文字を決定します だから、例えば使用するようにコマンドを変更するには#:それはこのようなものだsed -i '7s#.*#<param-value>http://localhost:8080/ASDF/services/REWS.REWSHttpSoap12Endpo‌​int/</param-value>#'
func0der

7
@meonlolを拡張するには、macOSにも-eif -iが指定されている必要があります。したがって、正しいコマンドは次のようになりますsed -e 'Ns/.*/replacement-line/' -i '' file.txt
ELLIOTTCABLE

44

実際にこのスクリプトを使用して、しばらく前に、当社のUNIXサーバー上のcronファイル内のコード行を置き換えました。通常のシェルスクリプトとして実行しましたが、問題はありませんでした。

#Create temporary file with new line in place
cat /dir/file | sed -e "s/the_original_line/the_new_line/" > /dir/temp_file
#Copy the new file over the original file
mv /dir/temp_file /dir/file

これは行番号ではなく、の前に行番号s/を置き、の代わりにワイルドカードを配置することで、簡単に行番号ベースのシステムに切り替えることができますthe_original_line


17
猫の役に立たない使用:sed -e "s/.../.../" /dir/file > /dir/temp_file
chepner 2012年

24
インタプリタ/コンパイラにとっては役に立たないかもしれませんが、人間がそれを読むことはできません。@Kyleのコードは左から右にうまく読みます。動詞は名詞の前にあるため、IMOで使用したイディオムは使用しません。
クレイトンスタンレー

1
以下のようなもので、たとえば、これら2つの行をマージする方法は、そこにあるsed -e "s/.../.../" /dir/file > /dir/file
Pubudu Dodangoda

22

4行目を「different」というテキストに置き換えたいとしましょう。AWKは次のように使用できます。

awk '{ if (NR == 4) print "different"; else print $0}' input_file.txt > output_file.txt

AWKは、入力を「フィールド」に分割された「レコード」と見なします。デフォルトでは、1行は1レコードです。 NR表示されたレコードの数です。 $0現在の完全なレコードを表します(一方$1、レコードの最初のフィールドなどです。デフォルトでは、フィールドは行の単語です)。

したがって、現在の行番号が4の場合、文字列 "different"を出力しますが、それ以外の場合は行を変更せずに出力します。

AWKでは、で囲まれたプログラムコード{ }は、各入力レコードで1回実行されます。

シェルがのようなものを解釈しようとしないようにするには、AWKプログラムを一重引用符で囲む必要があります$0

編集:以下のコメントで@chepnerからの短くてエレガントなAWKプログラム:

awk 'NR==4 {$0="different"} { print }' input_file.txt

レコード(つまり、行)番号4の場合のみ、レコード全体を文字列「different」に置き換えます。次に、すべての入力レコードについて、レコードを印刷します。

明らかに私のAWKスキルは錆びています!@chepner、ありがとうございます。

編集:そして@デニス・ウィリアムソンのさらに短いバージョンも見てください:

awk 'NR==4 {$0="different"} 1' input_file.txt

これがどのように機能するかはコメントで説明されています:は1常にtrueと評価されるため、関連するコードブロックは常に実行されます。ただし、関連付けられたコードブロックはありません。つまり、AWKは、行全体を印刷するというデフォルトのアクションを実行します。AWKは、このような簡潔なプログラムを許可するように設計されています。


3
少し短く:awk 'NR==4 {$0="different"} { print }' input_file.txt
chepner 2012年

2
@chepner:少し短い:awk 'NR==4 {$0="different"}1' input_file.txt
通知があるまで一時停止。

@DennisWilliamson、私はそれがどのように機能するかさえ知りません!その末尾1は何をしますか?(注:私はそれをテストしましたが、実際に機能します。方法がわからないだけです。)
steveha

1
無条件の印刷物を短縮する方法があると思いました!@stevaha:1は真の値であり、常に一致する「パターン」を意味します。また、一致のデフォルトのアクションは、現在の行を印刷することです。
chepner 2012年

19

このテストファイル(test.txt)

Lorem ipsum dolor sit amet,
consectetur adipiscing elit. 
Duis eu diam non tortor laoreet 
bibendum vitae et tellus.

次のコマンドは、最初の行を「改行テキスト」に置き換えます

$ sed '1 c\
> newline text' test.txt

結果:

newline text
consectetur adipiscing elit. 
Duis eu diam non tortor laoreet 
bibendum vitae et tellus.

詳細については、こちらをご覧ください

http://www.thegeekstuff.com/2009/11/unix-sed-tutorial-append-insert-replace-and-count-file-lines/


2
これが正解です。cフラグは、必要なことを正確に実行します(番号付きの行を特定のテキストで置き換えます)。
adelphus

stdoutでファイルをエコーし​​ないsedを使用した代替構文:stackoverflow.com/a/13438118/4669135
Gabriel Devillers

それは正しい答えですが、なぜ醜い改行ですか? sed '1 cnewline text' test.txt同様にそれを行います。
dev-null

7

bashでは、N、Mを行番号に、xxx yyyを必要なものに置き換えます

i=1
while read line;do
  if((i==N));then
    echo 'xxx'
  elif((i==M));then
    echo 'yyy'
  else
    echo "$line"
  fi
  ((i++))
done  < orig-file > new-file

編集

実際、このソリューションでは、文字「\ 0」、「\ t」、「\」でいくつかの問題があります。

"\ t"は、読み取りの前にIFS =を置くことで解決できます: "\"、-rで行末に

IFS= read -r line

しかし、「\ 0」の場合、変数は切り捨てられます。純粋なbashには解決策はありません。 ヌル文字(\ 0)を含む文字列をBashの変数に割り当てますが 、通常のテキストファイルにはヌル文字\ 0はありません

perlの方が良い選択です

perl -ne 'if($.==N){print"xxx\n"}elsif($.==M){print"yyy\n"}else{print}' < orig-file > new-file

純粋なBASHソリューションを試そうとは思いもしませんでした。
steveha

4
# Replace the line of the given line number with the given replacement in the given file.
function replace-line-in-file() {
    local file="$1"
    local line_num="$2"
    local replacement="$3"

    # Escape backslash, forward slash and ampersand for use as a sed replacement.
    replacement_escaped=$( echo "$replacement" | sed -e 's/[\/&]/\\&/g' )

    sed -i "${line_num}s/.*/$replacement_escaped/" "$file"
}

3

チェプナーからの素晴らしい答え。それはbashシェルで私のために働いています。

 # To update/replace the new line string value with the exiting line of the file
 MyFile=/tmp/ps_checkdb.flag

 `sed -i "${index}s/.*/${newLine}/" $MyFile`

here
index-Line
newLineno-置き換えたい新しい行ストリング。


同様に、以下のコードは、ファイル内の特定の行を読み取るために使用されます。これは実際のファイルには影響しません。

LineString=`sed "$index!d" $MyFile` 

ここで
!d-行no以外の行を削除します。そのため、ファイル$index にnoの行ストリングとして出力を取得$indexします。


しかし、私の結果はなぜ結果が表示されるの${newline}ですか?
sikisis 2015

1

Macでは私が使った

sed -i '' -e 's/text-on-line-to-be-changed.*/text-to-replace-the=whole-line/' file-name

-2

sedコマンドにパラメーターを渡すこともできます。

test.sh

#!/bin/bash
echo "-> start"
for i in $(seq 5); do
  # passing parameters to sed
  j=$(($i+3))
  sed -i "${j}s/.*/replaced by '$i'!/" output.dat
done
echo "-> finished"
exit 

元のoutput.dat:

a
b
c
d
e
f
g
h
i
j

./test.shを実行すると、新しいoutput.datが生成されます

a
b
c
replaced by '1'!
replaced by '2'!
replaced by '3'!
replaced by '4'!
replaced by '5'!
i
j

1
この例でループが必要なのはなぜですか?line=5; sed -i "${line}s/.*/replaced by '$i'!/" output.dat
Rob

あなたのこれのためのループを必要としない
chandu vutukuri
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.