2013-05-29 2 views
11

Я пытаюсь написать Баш скрипт, который будет делать следующее:Bash: Вставка содержимого одного файла в другой файл по образцу

  1. считывает содержимое из первого файла (в качестве первого аргумента)
  2. считывает содержимое из второго файла (в качестве второго аргумента)
  3. находит линию во втором файле с заданным шаблоном (в качестве третьего аргумента)
  4. вставляет текст из первого файла ко второму файлу после линии рисунка.
  5. печатает окончательный файл на экране.

Например:

first_file.txt:

111111 
1111 
11 
1 

second_file.txt:

122221 
2222 
22 
2 

картина:

2222 

выход:

122221 
111111 
1111 
11 
1 
2222 
111111 
1111 
11 
1 
22 
2 

Что я должен использовать для реализации этой функции в BASH?

Я написал код, но он не работает должным образом (почему?):

#!/bin/bash 

    first_filename="$1" 
    second_filename="$2" 
    pattern="$3" 

    while read -r line 
    do 
    if [[ $line=˜$pattern ]]; then 
      while read -r line2 
      do 
        echo $line2 
      done < $second_filename 
    fi 
    echo $line 
    done < $first_filename 
+0

Для 4-го пункта 'sed -i 'line, text ...'' может сделать это – fedorqui

+1

не могли бы вы дать небольшой пример? (ввод и ожидаемый выход) – michas

+0

Что происходит в вашем текущем коде? «Не работает» не очень хорошее описание ошибки –

ответ

1

Вам нужно пространство вокруг оператора =~. Сравнить:

[[ foo=~bar ]] 
[[ foo =~ bar ]] 

Это потому, что первое выражение, по существу, оценивается как «Является ли эта строка пустой?».

Кроме того, код использует small tilde, а не.

Несмотря на это, вы можете легко избавиться от внутреннего цикла. Просто замените весь бит while read -r line2 на cat -- "$second_filename".

Ваш последний echo $line верен только в том случае, если файл не конец символа новой строки (стандартный с * nix-инструментами). Вместо этого вы должны использовать while read -r line || [[ $line ~= '' ]]. Это работает с или без новой строки в конце.

Также Use More Quotes™.

+0

./replace_shell.sh: строка 9: ожидаемый условный двоичный оператор ./replace_shell.sh: строка 9: синтаксическая ошибка около '= ~ ' ./replace_shell.sh: строка 9:' \t, если [[$ line = ~ $ pattern]]; then ' – user2431907

+0

И когда я попытался сделать: «cat -« $ second_filename »: у меня есть ошибка: sed: 1:« file2.txt »: неверный код команды f – user2431907

+0

@ user2431907' = ~' не является то же, что и '= ~'. '~' [Unicode Small Tilde] (http://www.fileformat.info/info/unicode/char/02dc/index.htm). – l0b0

25

sed может сделать это без петель. Используйте свою команду r:

sed -e '/pattern/rFILE1' FILE2 

тестовой сессии:

$ cd -- "$(mktemp -d)" 
$ printf '%s\n' 'nuts' 'bolts' > first_file.txt 
$ printf '%s\n' 'foo' 'bar' 'baz' > second_file.txt 
$ sed -e '/bar/r./first_file.txt' second_file.txt 
foo 
bar 
nuts 
bolts 
baz 
+2

+1 Никогда не слышал о команде 'r'. Добавлен тестовый сеанс для проверки. – l0b0

+0

Есть ли способ убедиться, что он вставлен только один раз? – l0b0

+0

@ l0b0 'sed -e '1,/pattern/rFILE1' FILE2' вставляет его только один раз, но есть край, где' pattern' встречается в первой строке. В этом случае используйте GNU sed: 'sed '0,/pattern/rFILE1' FILE2' – potong

1

Это должно работать:

perl -lne 'BEGIN{open(A,"first_file.txt");@f=<A>;}print;if(/2222/){print @f}' second_file.txt 

Испытано:

> cat temp 
111111 
1111 
11 
1 
> cat temp2 
122221 
2222 
22 
2 
> perl -lne 'BEGIN{open(A,"temp");@f=<A>;}print;if(/2222/){print @f}' temp2 
122221 
111111 
1111 
11 
1 

2222 
111111 
1111 
11 
1 

22 
2 
> 
4

Использование AWK работы, а также.

Чтобы вставить перед строкой ### маркера ###:

// for each <line> of second_file.txt : 
// if <line> matches regexp ###marker###, outputs first_file.txt. 
// **without any condition :** print <line> 
awk '/###marker###/ { system ("cat first_file.txt") } \ 
    { print; } \' second_file.txt 

Чтобы вставить после ### маркера ### линии:

// for each <line> of second_file.txt : 
// **without any condition :** print <line> 
// if <line> matches regexp ###marker###, outputs first_file.txt. 
awk '{ print; } \ 
    /###marker###/ { system ("cat first_file.txt") } \' second_file.txt 

заменить ### маркер ### строка:

// for each <line> of second_file.txt : 
// if <line> matches regexp ###marker###, outputs first_file.txt. 
// **else**, print <line> 
awk '/###marker###/ { system ("cat first_file.txt") } \ 
    !/###marker###/ { print; }' second_file.txt 

Если вы хотите сделать в месте замены, используйте временный файл для того, что труба не начинается до того AWK имеет Rea d весь файл; добавить:

> second_file.txt.new 
mv second_file.txt{.new,} 
// (like "mv second_file.txt.new second_file.txt", but shorter to type !) 

Если вы хотите заменить внутри линии (замена только шаблон и сохранить остальную часть линии), подобное решение должно быть достижимо с СЭД вместо AWK.

+0

это работает, когда у вашей переменной есть какие-то кавычки, sed не может действительно иметь дело с этим – stringy05

+0

My awk (заменяющий маркер): awk -vf = "$ file" '/ ### marker ###/{system ("cat" f); next}; 1' - где $ file, файл для вставки, не должно быть пробелов в имени: / – schoettl

1

Я использую СЭД, как это и он работал как шарм

СЕПГ -i -e '/ шаблон/г filetoinsert' filetobeinserted

Что она делает это вставить 'filetoinsert' в «filetobeinserted» после строки с указанным рисунком

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

Смежные вопросы