Как заменить строку в 5-й строке нескольких текстовых файлов?

22

Я хочу заменить 5-ю строку нескольких текстовых файлов ( file1.txt, file2.txt, file3.txt, file4.txt ) строкой «Доброе утро» с помощью одной команды терминала.

Все текстовые файлы находятся на моем ~/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

    Объяснение:

    • -i: вызывает perlредактирование файлов на месте, изменение исходного файла.

      Если -iсопровождается суффиксом расширения файла, то резервная копия создается для каждого изменяемого файла. Пример: -i.bakсоздает модификацию file1.txt.bakif file1.txtво время выполнения.

    • -p: означает прочитать входной файл построчно, применить скрипт и распечатать его.

    • -e: позволяет передать скрипт из командной строки.

    • s/.*/ Good Morning /: Это заменит текст в текущей строке ( .*) добрым утром.

    • $.является специальной переменной Perl, которая содержит текущий номер строки входного файла. Таким образом, s/foo/bar/ if $.==5, означает замену fooс barтолько на 5 - й линии.

  2. СЭД

    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. В awk, NRэто номер текущей строки и $0является содержанием текущей строки. Таким образом, скрипт заменит строку ( $0) на «Доброе утро» только на 5-й строке. 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-й строки до конца файла

    Скобки ( )вокруг этих трех команд позволяют вам захватить выходные данные всех трех (так, первые 4 строки, затем «Доброе утро», затем остальные строки) и перенаправить их в файл.

terdon
источник
23

Вы можете использовать sed:

sed '5s/^/Good morning /' file

добавил бы Good morningв пятую строку файла.

Если вы хотите заменить содержимое в строке 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!

devnull
источник
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, мы записываем строку, которая отличается. Остальное - просто заменить старый файл временным файлом Demo:

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

То же самое может быть достигнуто с помощью понимания списка. Ниже приведен однострочник того же скрипта:

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

Вы можете использовать Vim в режиме Ex:

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

Ниже приведен скрипт bash, который завершает процесс perl, предложенный в этом ответе.

Пример:

/ TMP / это

console:
  enabled:false

Затем выполните следующее:

$ search_and_replace_on_line_of_file.sh false true 2 /tmp/it

и файл теперь содержит

/ TMP / это

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 
Брэд Паркс
источник