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

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

Все текстовые файлы расположены на моем ~/Desktop.

Примечание: Мой рабочий стол состоит из 6 .txt файлов. Я хочу применить изменение в вышеупомянутых 4 текстовых файлах только.

22
задан 15 March 2014 в 06:29

5 ответов

Вот несколько подходов. Я использую расширение фигурной скобки (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 создает a file1.txt.bak если file1.txt изменяется во время выполнения.

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

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

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

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

  2. sed

    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) который затем переименован для перезаписи оригинала. Цикл удара for f in file{1..4}.txt; do ... ; done просто проходит каждый из file{1..4}.txt, сохранение текущего имени файла как $f. В awk, NR текущий номер строки и $0 содержание текущей строки. Так, сценарий заменит строку ($0) с "Добрым утром" только на 5-й строке. 1; awk для "печати строка".

    Версии ¹Newer делают, поскольку 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-й строки в конец файла

    Круглые скобки ( ) вокруг тех трех команд позволяют Вам получать вывод всех трех (так, 1-е 4 строки, затем "Доброе утро", затем остальная часть строк) и перенаправлять их в файл.

40
ответ дан 23 November 2019 в 01:30

Можно использовать 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 запись, если изменения были внесены (они имеют), и выйдите

1
ответ дан 16 November 2019 в 12:08

Следующее является сценарием удара, который оборачивает процесс жемчуга, предложенный в этом ответе

Пример:

/tmp/it

console:
  enabled:false

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

$ search_and_replace_on_line_of_file.sh false true 2 /tmp/it

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

/tmp/it

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 
0
ответ дан 16 November 2019 в 12:08

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

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

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

Если Вы хотите заменить содержание на строке 5 вместо этого, сказать:

sed '5s/.*/Good morning/' file

Если Вы хотели сохранить изменения в оперативном файле, используйте -i опция:

sed -i '5s/.*/Good morning/' file

sed может обработать больше чем один файл за один раз. Можно просто добавить больше имен файлов на конец команды. Можно также использовать расширения удара для соответствия конкретным файлам:

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

23
ответ дан 23 November 2019 в 01:30

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

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

2
ответ дан 23 November 2019 в 01:30

Другие вопросы по тегам:

Похожие вопросы: