web-dev-qa-db-ja.com

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

ファイル内の1行全体をbashスクリプトで置き換えたいという状況があります。行番号は常に同じなので、ハードコーディングされた変数にすることができます。

その行の一部のサブストリングを置き換えようとしているのではなく、その行全体を新しい行に置き換えたいだけです。

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

133
user788171

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

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

Nは、ターゲットの行番号に置き換えます。これは元のファイルの行を置き換えます。変更したテキストを別のファイルに保存するには、-iオプションを削除します。

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

私は実際にこのスクリプトを使用して、しばらく前に、当社の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の代わりにワイルドカードを置くことで、行番号ベースのシステムに簡単に切り替えることができる。

42
Kyle

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回実行されます。

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

編集:以下のコメントで@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はこのような簡潔なプログラムを許可するように設計されています。

18
steveha

このテストファイル(test.txt)を考えます

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

次のコマンドは最初の行を "newline text"に置き換えます

$ 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/

13
Eric Robinson

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では解決策はありません。 null文字(\ 0)を含む文字列をBashの変数に代入する しかし、通常のテキストファイルにはあります。ヌル文字なし\ 0

Perlが良い選択でしょう

Perl -ne 'if($.==N){print"xxx\n"}elsif($.==M){print"yyy\n"}else{print}' < orig-file > new-file
7
# 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"
}
2
Daniel Bigham

Chepnerからの素晴らしい答え。それは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`

ここに
index - 行番号
newLine - 置換したい改行文字列。


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

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

ここに
!d - 行番号$index以外の行を削除します。したがって、出力はファイル内のno $indexの行ストリングとして取得されます。

2

私が使ったMacでは

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