2012-06-21 6 views
87

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

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

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

ответ

123

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

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

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

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

Есть ли способ, чтобы сделать СЭД изменить файл в вопросе вместо сброса на экран? – user788171

+0

Теперь я попал в sed: незаконный вариант - я есть исправление для этого? – user788171

+0

sudo port install sed? ты на маке? если это так, просто используйте версию * nix –

14

Давайте предположим, что вы хотите заменить строку 4 с текстом «другом». Вы можете использовать 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 Уильямсон:

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

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

+2

Немного короче:' awk 'NR == 4 {$ 0 = "different"} { print} 'input_file.txt'. – chepner

+1

@chepner: немного короче: 'awk 'NR == 4 {$ 0 =" different "} 1' input_file.txt' –

+0

@DennisWilliamson, я даже не знаю, как это работает! Что делает этот завершающий «1»? (Примечание: я тестировал его, и он действительно работает! Я просто не понимаю, как это сделать.) – steveha

5

в Баше, заменить N, M по номерам строк и ххх его тем, что вы хотите

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 

EDIT

На самом деле в этом решении есть некоторые проблемы, с символами «\ 0» "\ т" и "\"

"\ т", можно решить, поставив IFS = перед чтением: "\", в конце строки с -r

IFS= read -r line 

но для «\ 0», то переменная усечена, не существует решение в чистом Баше: Assign string containing null-character (\0) to a variable in Bash Но в обычном текстовом файле нет нулевого символа \ 0

Perl будет лучшим выбором

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

Я даже не думал о попытке чистого решения BASH! – steveha

9

Учитывая этот тестовый файл (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/

+1

Это должен быть правильный ответ. Флаг c выполняет именно то, что требуется (заменяет пронумерованную строку заданным текстом). – adelphus

+0

Альтернативный синтаксис с sed, который не отвечает на файл на stdout: https://stackoverflow.com/a/13438118/4669135 –

38

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

#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.

+13

Бесполезное использование cat: 'sed -e" s /.../.../ "/ dir/file>/dir/temp_file' – chepner

+16

Возможно, для интерпретатора/компилятора бесполезно, но не для человека, читающего его. @ Код Кайла хорошо читается слева направо; идиома, которую вы использовали ИМО, нет, из-за того, что глагол находится перед существительным. –

+0

Есть ли способ объединить эти две строки, например, что-то вроде 'sed -e 's /.../.../"/dir/file>/dir/file' –

1

Отличный ответ от 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 - Line нет
newLine - новая строка строка, которую мы хотим заменить.


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

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

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

+0

, но это мой bash, почему результат только показывает '$ {newline}'? – sikisis

1

# 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" 
 
}

-1

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

Почему вам нужен цикл для этого примера, просто обфускает решение? '' Линия = 5; sed -i "$ {line} s /.*/ заменено на '$ i'! /" output.dat'' – Rob

Смежные вопросы