2015-08-26 6 views
4

Я могу сделать это, используя следующий пример. Первая команда будет выводить строки 16 ... 80 от file1 до patch, в то время как второй будет вставлять содержимое patch после строки 18 в file2:SED: копировать строки из файла в определенную строку в другом файле

sed -n 16,80p file1>patch 
sed -i 18rpatch file2 

Однако, я хотел бы, чтобы скопировать непосредственно из одного файла к другому без использования временного файла между ними, в одной команде с помощью sed (не awk и т. д.). Я уверен, что это возможно, просто не знаю, как это сделать.

+0

Его невозможно. – 123

+0

@ User112638726: Почему бы и нет ?! – mYself

+0

Ну, может быть, если вы знаете точное количество строк в каждом файле и не хотите использовать -i, но это больше усилий, чем у вас в настоящее время. В качестве альтернативы вы можете просто использовать awk. – 123

ответ

4

Выполнение этого с помощью sed требует некоторых дополнительных обвинений оболочки. Предполагая Баш, вы могли бы использовать

sed -i 18r<(sed '16,80!d' file1) file2 

Где <(sed '16,80!d' file1) заменяется на имя трубы, из которой выход sed '16,80!d' file1 может быть прочитан.

Как правило, я чувствую, что лучше делать это с помощью awk (если немного дольше), потому что awk лучше оборудован для обработки нескольких входных файлов. Например:

awk 'NR == FNR { if(FNR >= 16 && FNR <= 80) { patch = patch $0 ORS }; next } FNR == 18 { $0 = patch $0 } 1' file1 file2 

Это работает следующим образом:

NR == FNR {      # While processing the first file 
    if(FNR >= 16 && FNR <= 80) { # remember the patch lines 
    patch = patch $0 ORS 
    } 
    next       # and do nothing else 
} 
FNR == 18 {      # after that, while processing the first file: 
    $0 = patch $0     # prepend the patch to line 18 
} 
1         # and print regardless of whether the current 
            # line was patched. 

Однако этот подход не поддается на месте редактирования файлов. Обычно это не проблема; Я бы просто использовать

cp file2 file2~ 
awk ... file1 file2~ > file2 

с дополнительным преимуществом наличия резервной копии в случае, если вещи идут грушевидной формы, но в конце концов, это до вас.

+0

Оба 'sed' и' awk' просто выводят все в stdout вместо сохранения изменений в файл. Пожалуйста, отредактируйте свой ответ, чтобы это отразить. Кстати, вы тот же человек, что и @ User112638726, с которым я разговаривал раньше? – mYself

+0

А, я читал прямо над частью редактирования на месте. Ответ обновлен. Было бы технически возможно с GNU awk 4.1 или новее адаптировать подход awk к редактированию на месте, но поскольку есть несколько входных файлов, из которых только один должен быть изменен, я не думаю, что это очень хорошая идея ; вам придется переписать один файл с собственным содержимым, и это оставляет возможность для вещей идти более ужасно неправильно, если что-то было упущено. И нет, я не пользователь112638726. – Wintermute

+0

Это побочный вопрос, но в чем проблема с редактированием на месте с awk, это не проблема с sed? Согласно [этому вопросу] (/ questions/16529716/awk-save-changes-changes-inplace), 'gawk' может это сделать (т. Е. Имеет такую ​​же опцию -i, что и sed). Кроме того, спасибо за разъяснение вашей личности. Я был немного смущен, что вы ответили на вопрос сразу после его предложения. – mYself

0
sed -i '1,15 d 
     34 r patch 
     81,$ d' YourFile 

# oneliner version 
sed -i -e '1,15 d' -e '34 r patch' -e '81,$ d' YourFile 
  • порядок линии не имеет значения.
  • Вы можете адаптировать немного или партии оно с переменной как этот

sed -i "1,16 d $((16 + 18)) r patch 81,$ d" YourFile

но добавить некоторую безопасность относительно подсчета линии в этом случае.

  • если r линия более чем 1 линия, следующая строка по-прежнему отсчитывается от первоначального места и конечного файла больше, чем 80 - 16 линий

я не совсем тест на линии приняты, исключены или модифицированный (например, 34 является 18-й строки обрезанного файла), но Principe тем же

Explaination для ссылок индексных линий, используемый в данном примере:

  • 1,15 - строка заголовка для удаления, поэтому файл берет линии от 16 в этом случае
  • 34 - это линия для изменения содержимого и является результатом 18-й строки ПОСЛЕ первого нового контента (строка 16 в нашем случае), поэтому 16 + 18 = 34
  • 81,$ - обратные линии для удаления, $ означает последнюю строку, а 81 - первую строку (после 80 взятых) нежелательных завершающих линий.
+0

Это решение не работает (это просто испортит выходной файл). Вы можете исправить это, пожалуйста? Кроме того, вместо новых строк используйте '-e', поэтому вместо трех будет использоваться только одна строка. – mYself

+0

какой ОС, отлично работать на моем Linux и на AIX (а не на -i)? вам может понадобиться аргумент после '-i', как на MAC. Я просто адаптирую номер строки (16 -> 15, вы просите взять из строки 16 в комплекте) – NeronLeVelu

+0

Привет. Я снова попытался использовать предложенное вами изменение с теми же результатами. Мой дистрибутив Trisquel 7.0 (основанный на Ubuntu 14.04). Это точная команда, которую я использовал: 'sed -i -e $ ((1847 + 1663)) r ../ VirtualBox-4.1.40/Config.kmk -e 1,1662d -e '1681, $ d' Config. kmk'. Файлы можно получить здесь: http://download.virtualbox.org/virtualbox/5.0.2/VirtualBox-5.0.2.tar.bz2. Что я делаю не так? – mYself

3

я сделал что-то подобное с помощью:

head -80 file | tail -16 > patch 

Проверьте документацию для локальных версий голов и хвоста и изменить два целых число в соответствии с вашими требованиями.

+0

tail -20 подсчитывает 20 строк с конца файла, tail -n -20 подсчитывает 20 строк от начало файла. –