Код Unix хотел скопировать файл шаблона и заменить строки в файле шаблона в скопированных файлах - PullRequest
4 голосов
/ 28 марта 2012

У меня есть 2 файла:

File_1.txt:

John
Mary
Harry
Bill

File_2.txt:

My name is ID, and I am on line NR of file 1.

Я хочу создать четыре файла, которые выглядят так:

Output_file_1.txt:

My name is John, and I am on line 1 of file 1.

Output_file_2.txt:

My name is Mary, and I am on line 2 of file 1.

Output_file_3.txt:

My name is Harry, and I am on line 3 of file 1.

Output_file_4.txt:

My name is Bill, and I am on line 4 of file 1.

Обычно я бы использовал следующую команду sed для этого:

for q in John Mary Harry Bill
do  
sed 's/ID/'${q}'/g' File_2.txt > Output_file.txt
done

Но это только заменит идентификатор для имени и не будет включать строку nr в File_1.txt. К сожалению, мои навыки bash не идут намного дальше ... Какие-нибудь советы или предложения для команды, которая включает и файл 1 и 2? Мне действительно нужно включить файл 1, потому что на самом деле файлы намного больше, чем в этом примере, но я думаю, что смогу выяснить остальную часть кода, если знаю, как это сделать с этим, возможно, более простым примером ... заранее спасибо!

Ответы [ 6 ]

9 голосов
/ 28 марта 2012

Как насчет:

n=1
while read q
  do  
  sed -e 's/ID/'${q}'/g' -e "s/NR/$n/" File_2.txt > Output_file_${n}.txt
  ((n++))
done < File_1.txt

См. Расширенное руководство по созданию сценариев Bash по перенаправлению ввода в кодовые блоки и, возможно, раздел в двойных скобках для дальнейшего чтения.

3 голосов
/ 29 марта 2012

А как насчет awk?

[ghoti@pc ~]$ cat file1
John
Mary
[ghoti@pc ~]$ cat file2
Harry
Bill
[ghoti@pc ~]$ cat merge.txt 
My name is %s, and I am on the line %s of file '%s'.
[ghoti@pc ~]$ cat doit.awk 
#!/usr/bin/awk -f

BEGIN {
  while (getline line < "merge.txt") {
    fmt = fmt line "\n";
  }
}

{
  file="Output_File_" NR ".txt";
  printf(fmt, $1, FNR, FILENAME) > file;
}

[ghoti@pc ~]$ ./doit.awk file1 file2
[ghoti@pc ~]$ grep . Output_File*txt
Output_File_1.txt:My name is John, and I am on the line 1 of file 'file1'.
Output_File_2.txt:My name is Mary, and I am on the line 2 of file 'file1'.
Output_File_3.txt:My name is Harry, and I am on the line 1 of file 'file2'.
Output_File_4.txt:My name is Bill, and I am on the line 2 of file 'file2'.
[ghoti@pc ~]$ 

Если вы действительно хотите, чтобы ваши имена файлов были пронумерованы, мы тоже можем это сделать.

Что здесь происходит?

Сценарий awk НАЧИНАЕТСЯ, прочитав в файле merge.txt и добавив его в переменную "fmt", строка за строкой (разделенные символами новой строки).Это делает fmt строку формата, совместимую с printf.

Затем для каждой строки во ваших входных файлах (указанных в командной строке) выбирается выходной файл (NR - текущее число записей, охватывающее все файлы.).Функция printf () заменяет каждый %s в переменной fmt одним из своих параметров.Вывод перенаправляется в соответствующий файл.

grep просто показывает все содержимое файлов с их именами файлов.

1 голос
/ 29 марта 2012

Небольшая модификация, необходимая в вашем скрипте. Вот и все.

pearl.306> cat temp.sh
#!/bin/ksh

count=1
cat file1|while read line
do
sed -e "s/ID/${line}/g" -e "s/NR/${count}/g" File_2.txt > Output_file_${count}.txt
count=$(($count+1))
done
pearl.307>

pearl.303> temp.sh
pearl.304> ls -l Out*
-rw-rw-r--   1 nobody   nobody        59 Mar 29 18:54 Output_file_1.txt
-rw-rw-r--   1 nobody   nobody        58 Mar 29 18:54 Output_file_2.txt
-rw-rw-r--   1 nobody   nobody        58 Mar 29 18:54 Output_file_3.txt
-rw-rw-r--   1 nobody   nobody        58 Mar 29 18:54 Output_file_4.txt
-rw-rw-r--   1 nobody   nobody        58 Mar 29 18:54 Output_file_5.txt
pearl.305> cat Out*
My name is linenumber11, and I am on the line 1 of file 1.
My name is linenumber2, and I am on the line 2 of file 1.
My name is linenumber1, and I am on the line 3 of file 1.
My name is linenumber4, and I am on the line 4 of file 1.
My name is linenumber6, and I am on the line 5 of file 1.
pearl306>
1 голос
/ 29 марта 2012
  • Считывание имен в массив.
  • получение длины массива
  • итерация по массиву

Подготовка к тесту:

echo "John
Mary
Harry
Bill
" > names 

Имена и номера:

name=($(<names))
max=$(($(echo ${#name[*]})-1))
for i in $(seq 0 $max) ; do echo $i":"${name[i]}; done

с шаблоном:

for i in $(seq 0 $max) ; do echo "My name is ID, and I am on the line NR of file 1." | sed "s/ID/${name[i]}/g;s/NR/$((i+1))/g";   done 
My name is John, and I am on the line 1 of file 1.
My name is Mary, and I am on the line 2 of file 1.
My name is Harry, and I am on the line 3 of file 1.
My name is Bill, and I am on the line 4 of file 1.
1 голос
/ 29 марта 2012

TXR:

$ txr merge.txr
My name is John, and I am on the line 1 of file1.
My name is Mary, and I am on the line 2 of file1.
My name is Harry, and I am on the line 3 of file1.
My name is Bill, and I am on the line 4 of file1.

merge.txr:

@(bind count @(range 1))
@(load "file2.txt")
@(next "file1.txt")
@(collect)
@name
@(template name @(pop count) "file1")
@(end)

file2.txt:

@(define template (ID NR FILE))
@(output)
My name is @ID, and I am on the line @NR of @FILE.
@(end)
@(end)
1 голос
/ 29 марта 2012

Это может работать для вас:

sed '=' File_1.txt |
sed '1{x;s/^/'"$(<File_2.txt)"'/;x};N;s/\n/ /;G;s/^\(\S*\) \(\S*\)\n\(.*\)ID\(.*\)NR\(.*\)/echo "\3\2\4\1\5" >Output_file_\1.txt/' |
bash
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...