2017-02-20 21 views
3

У меня есть многострочная переменная, которую я захватил из STDOUT.
Я хочу вставить команду эха, используя эту многострочную переменную, в строку 15 в другом скрипте (цели).Использование многострочной переменной в команде sed

#!/bin/bash 
TEST=`cat foo` 

echo "$TEST" 

sed -i "15i echo \"$TEST\" > someotherfile" target 

Содержание обув:

apples 
oranges 
bananas 
carrots 

Я думал, что СЕПГ команда чтения в строке каналов, которые я подтвердил свою F имеет:

[email protected]$ cat foo | tr -cd '\n' | wc -c 
4 

Когда я бег моего сценария test.sh , Я вижу, что находится в $TEST, но я получаю сообщение об ошибке для команды sed:

[email protected]$ ./test.sh 
apples 
oranges 
bananas 
carrots 
sed: -e expression #1, char 18: unknown command: `o' 

Что я делаю неправильно? Спасибо заранее.

+0

Вы можете добавить полный ввод/вывод образца? 'TEST' имеет несколько значений строки строки, и вы добавляете строку до и после ... так что для меня немного неясно ... для вставки только содержимого из файла, используйте команду' r' ... 'sed ' 14r foo 'target' -> вставляет содержимое файла foo с 15-й строки вперед, чтобы ввести целевой файл – Sundeep

ответ

1

Try:

Solution1:

awk 'NR==15{print;system("cat foo");next} 1' Input_file 

Нет необходимости, чтобы получить полный файл в переменную, мы могли бы просто напечатать его в зависимости от того линия input_file вы хотите напечатать.

Solution2:

line=15; sed -e "${line}r foo" target 

Или (в режиме сценария)

cat script.ksh 
line=15; 
sed -e "${line}r foo" target 

Где можно изменить номер строки, где вы хотите вставить строки из другого файла.

0

Команда i в sed вставляет строки текста, заканчивающиеся символом новой строки, вплоть до линии, которая не заканчивается обратным слэшем. Команды a и c аналогичны. Классическому sed не нравится, когда первая строка появляется в той же строке, что и команда i; GNU sed не такой суетливый.

Если вы пишете команду вручную, вы должны были бы написать:

15i\ 
echo "apples\ 
oranges\ 
bananas\ 
carrots" > someotherfile 

На вопрос сейчас «как вы хотите, чтобы создать этот файл, учитывая foo содержит список имен?». Иногда полезно использовать sed для генерации сценария sed. Тем не менее, это также может быть сложным, если вам нужно получить обратную косую черту на концах линий, которые подчиняются команде i (или a или c), и проще обойти эту проблему.

{ 
    echo "15i\\" 
    sed -e '1s/^/echo "/' -e 's/$/\\/' -e '$s/\\$/" > someotherfile/' foo 
} | sed -f /dev/stdin target 

ГНУ sed может прочитать его сценарий из стандартного ввода с помощью -f -; BSD (macOS) sed не нравится, но вместо этого вы можете использовать -f /dev/stdin (что также работает с GNU sed), по крайней мере, в системах, где есть /dev/stdin.

0

Предполагается, что GNUsed подразумевается синтаксисом, используемым в вопросе.

#!/bin/bash 

# Read contents of file 'foo' into shell variable $test. 
test=$(<foo) 

# \-escape the newlines in $test for use in Sed. 
testEscapedForSed=${test//$'\n'/\\$'\n'} 

sed -i "15i echo \"$testEscapedForSed\" > someotherfile" target 
  • Ваша проблема в том, что прохождение Многострочного строки для sed функций, таких как i (вставка) требует новой строки, встроенной в этих строках, чтобы быть \ убежали, так что sed знает где заканчивается строка, и запускаются дополнительные команды, если они есть.

    • А (нестандартный) parameter expansion используется, чтобы заменить все символы новой строки в $test с собой префиксом \, используя ANSI C-quoted string$'\n', чтобы генерировать фактические новой строки символов.
  • Также обратите внимание:

    • Я переименовал TEST к test, потому что all-uppercase shell-variable names should be avoided.

    • Я использовал современный синтаксис командной строки $(..) вместо устаревшего синтаксиса `...`.

    • $(<foo) - это несколько более эффективный, хотя и нестандартный способ чтения содержимого файла за один раз.

0

Интересный вопрос. Как уже упоминалось, вся история для sed, чтобы иметь возможность вставлять многострочный текст в другой файл, состоит в том, что этот новый многострочный текст должен иметь на самом деле литерал \n для разрывов строк.

Таким образом, мы можем использовать СЭД, чтобы преобразовать реальные новые символы строки в буквальном \n:

$ a=$(tr '\n' '\\' <file3 |sed 's#[\]$##' |sed "s#[\]#\0n#g") 
#Alternative: a=$(sed "s#[\]#\0n#g" <(sed 's#[\]$##' <(tr '\n' '\\' <file3))) 
$ echo "$a" 
apples\noranges\nbananas\ncarrots 

Как это перевод работы:
* Во-первых, мы заменим все новые линии с одной обратной косой черты с помощью tr
* Тогда мы удаляем обратную косую черту с конца строки
* Затем мы заменяем все остальные обратные косые черты обратным слэшем и символом n char.

Поскольку в настоящее время переменная $a содержит литерал \n между строк, СЭД будет переводить их обратно actuall новые линии:

$ cat file4 
Line1 
line2 
line3 
$ sed "2i $a" file4 
Line1 
apples 
oranges 
bananas 
carrots 
line2 
line3 

Результат:
многострочного замена может быть сделано с двумя командами:

$ a=$(tr '\n' '\\' <file3 |sed 's#[\]$##' |sed "s#[\]#\0n#g") 
$ sed "2i $a" file4 

sed 2i означает вставить текст перед строкой2. 2a может использоваться для вставки чего-либо после строки2.

Примечание:
Согласно this post который, кажется, дубликат, перевод новых строк в буквальном \ п кажется, что может быть сделано только с:

a=$(echo ${a} | tr '\n' "\\n") 

Но этот метод никогда не работал в моей системе.

Remark2:
СЭДА операции sed "2i $a" = вставить переменные $ а перед строкой 2, может быть также выражен как sed "1 s/.*/\0\n$a/" = заменить все символы из первой строки с теми же символами \0 плюс новой линией \n плюс содержимым переменной $a => вставить $ a после строки1 = вставить $ a перед линией2.