Как заменить всю строку в текстовом файле по номеру строки

У меня есть ситуация, когда я хочу, чтобы bash script заменил всю строку в файле. Номер строки всегда один и тот же, поэтому это может быть жестко закодированная переменная.

Я не пытаюсь заменить некоторую подстроку в этой строке, я просто хочу полностью заменить эту строку новой строкой.

Существуют ли какие-либо методы bash для этого (или что-то простое, которое может быть выбрано в .sh script).

Ответ 1

Не самое большое, но это должно работать:

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

где N следует заменить номером вашей целевой линии. Это заменяет строку в исходном файле. Чтобы сохранить измененный текст в другом файле, отпустите параметр -i:

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

Ответ 2

Я действительно использовал этот script, чтобы заменить строку кода в файле cron на наших серверах UNIX на некоторое время назад. Мы выполнили его как обычную оболочку script и не имели проблем:

#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 подстановочный знак.

Ответ 3

Предположим, вы хотите заменить строку 4 текстом "different". Вы можете использовать AWK так:

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

AWK считает, что входные данные являются "записями", разделенными на "поля". По умолчанию одна строка - одна запись. NR - количество записей. $0 представляет текущую полную запись (в то время как $1 является первым полем из записи и т.д., по умолчанию поля являются словами из строки).

Итак, если текущий номер строки равен 4, напечатайте строку "different", но в противном случае напечатайте строку без изменений.

В AWK программный код, заключенный в { }, запускается один раз на каждой входной записи.

Вам нужно процитировать программу AWK в одиночных кавычках, чтобы оболочка не пыталась интерпретировать такие вещи, как $0.

EDIT: более короткая и более элегантная программа AWK от @chepner в комментариях ниже:

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

Только для записи (т.е. строка) номер 4, замените всю запись строкой "другой". Затем для каждой входной записи распечатайте запись.

Ясно, что мои навыки AWK ржавы! Спасибо, @chepner.

EDIT: см. также более короткую версию от @Dennis Williamson:

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

Как это работает, объясняется в комментариях: 1 всегда оценивает значение true, поэтому всегда выполняется соответствующий блок кода. Но не существует связанного блока кода, что означает, что AWK выполняет свое действие по умолчанию только для печати всей строки. AWK предназначен для использования таких коротких программ.

Ответ 4

Данный тестовый файл (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/

Ответ 5

в 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

Ответ 6

Отличный ответ от Chepner. Он работает для меня в bash Shell.

 # 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 - Строка no
      newLine - новая строка строки, которую мы хотим заменить.


Аналогично ниже код используется для чтения определенной строки в файле. Это не повлияет на фактический файл.

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

здесь
      !d - удалит строки, отличные от строки $index      Таким образом, мы получим вывод в виде строки строки $index в файле.

Ответ 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"
}

Ответ 8

На mac я использовал

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

Ответ 9

Вы можете даже передать параметры команде 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 

orignial 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