Как использовать sed или другие команды для замены существующей строки другой строкой для каждой строки - PullRequest
0 голосов
/ 27 января 2020
for i in 1 2 3 4 5 6 7; do
 sed "s/\number\b/& =$i/" print.txt 
done

print.txt содержит:

number elephant
number giraffe
number dogs
number cats
number mouse
number pigs
number snake

Как заменить слово / строку в ОДНОЙ строке текстового файла в a для l oop без изменения каждой строки? Всякий раз, когда я запускаю свой сценарий, он превращает все «число» в одно заданное c число, и к моменту выполнения последней итерации все «число» заменяется на 7. Я понимаю, почему это происходит, просто не знаю, как это сделать. почини это.

В этом простом примере я хочу, чтобы он выводился так:

1 elephant
2 giraffe
3 dogs
4 cats
5 mouse
6 pigs
7 snake

Но, скажем, по моему для l oop, он определяет переменную, которая будет козлом, и вторая итерация - курица, я хочу, чтобы свиньи были заменены на козу, а змея - на курицу, как мне сделать это в моем для l oop?

Ответы [ 2 ]

1 голос
/ 27 января 2020

Если я понимаю, что вы хотите заменить "number" в каждой строке увеличивающимися значениями 1-7, то вам вообще не нужно (или не нужно) al oop. Просто передайте результат sed удаления строки "number" из начала каждой строки до nl -w1 -s' ' для нумерации строк. Пример:

$ sed 's/^number\s*//' print.txt | nl -w1 -s' '
1 elephant
2 giraffe
3 dogs
4 cats
5 mouse
6 pigs
7 snake

( примечание: вы также можете использовать grep -o '\w*$' print.txt | nl -w1 -s' ')

Вы можете настроить числовой формат и разделитель с помощью параметров. Смотри man 1 nl .

Почему вы не хотите, чтобы все oop? Сколько раз вы вызываете sed и порождаете дополнительный подоболочек внутри вашего l oop? (одна на итерацию). Это ужасно неэффективно. Каждый раз, когда вы зацикливаетесь в оболочке, вы хотите минимизировать количество подоболочек, порожденных в вашем l oop.

Можете ли вы сделать это с помощью al oop, как вы пытались? Конечно, но это одно из наименее эффективных решений, которое вы можете придумать. Чтобы все это работало в oop, вы должны ограничить количество операций для каждой итерации требуемой строкой в ​​файле. Вы можете сделать это путем подавления нормального вывода и вывода только строки, которую вы изменили, например,

for i in 1 2 3 4 5 6 7; do
    sed -n "${i}s/number/$i/p" print.txt
done

(, но НЕ ДЕЛАЙТЕ так ... )

Если вы хотите еще более эффективное решение, которое устраняет трубу и дополнительный подоболочек, просто используйте awk и счетчик (n ниже), например,

$ awk -v n=1 '{print n++ " " $2}' print.txt
1 elephant
2 giraffe
3 dogs
4 cats
5 mouse
6 pigs
7 snake

Вы также можете дополнительно контролировать число и Формат разделителя, используя printf вместо print выше.

Дайте мне знать, если у вас есть вопросы или вы хотите что-то другое.


Ответ на комментарий Вопрос

Если у вас есть 3 строки с одинаковым полем, которые вы хотите изменить на что-то другое, вы сначала должны знать, что вы хотите изменить идентичные поля на. Это означает, что у вас должна быть таблица замены или таблица поиска замен где-то.

Скажите, что ваш текстовый файл на самом деле:

$ cat print2.txt
number elephant
number giraffe
number dogs
number cats
number pigs
number pigs
number pigs

И Вы хотите изменить строки 5, 6, 7 с "pigs" на "goat", "cow", "chicken" в этом порядке, затем с помощью awk вы можете считать значения замены в массив и произвести замены, используя счетчик, чтобы определить, какую замену использовать. (ниже мы просто заполняем массив тремя заменами)

Вы можете сделать что-то похожее на следующее:

awk 'BEGIN {n=1; rep[1]="goat"; rep[2]="cow"; rep[3]="chicken"}
    $2=="pigs"{$2=rep[n++]}
    {print}
' print2.txt

Копирование / вставка в командной строке приведет к:

$ awk 'BEGIN {n=1; rep[1]="goat"; rep[2]="cow"; rep[3]="chicken"}
>     $2=="pigs"{$2=rep[n++]}
>     {print}
> ' print2.txt
number elephant
number giraffe
number dogs
number cats
number goat
number cow
number chicken

Так что вы можете делать то, что просите в комментарии - вам просто нужно заранее знать, на что вы будете заменять повторы.

0 голосов
/ 27 января 2020

Чистое bash решение для оболочки без каких-либо внешних инструментов / утилит.

!/bin/bash

n=1
while read -r line; do
  printf '%s\n' "${line//number/"$n"}"
  ((n++))
done < print.txt

Использование POSIX sh.

#!/bin/sh

n=1
while read -r line; do
  printf '%d. %s\n' "$n" "${line#* }"
  n=$((n+1))
done < print.txt

Для небольшого размера / набора данных / Ввод это должно быть хорошо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...