2014-01-20 2 views
1

Я пытаюсь кота файл, чтобы создать копию себя, но в то же время заменить некоторые значенияПочему эта команда sed ничего не делает?

моя команда:

cat ${FILE} | sed "s|${key}|${value}|g" > ${TEMP_FILE} 

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

Но если я использую обычную строку не переменную, она отлично работает для одного типа ключа - то есть:

cat ${FILE} | sed "s|example_key|${value}|g" > ${TEMP_FILE} 

Экземпляры example_key внутри файла заменяются что то, что я хочу.

Однако, когда я пытаюсь использовать параметр массива $ key, он ничего не делает. Не знаю, почему :-(

использования

Команда:

declare -a props 
... 
.... 
for x in "${props[@]}" 
do 
    key=`echo "${x}" | cut -d '=' -f 1` 
    value=`echo "${x}" | cut -d '=' -f 2` 


    # global replace on the $FILE 
    cat ${FILE} | sed "s|${key}|${value}|g" > ${TEMP_FILE} 
    #cat ${FILE} | sed "s|example_key|${value}|g" > ${TEMP_FILE} 

done 

элементы массива хранятся в следующем формате: $ ключ = значение $

+0

Можете ли вы попробовать: 'sed 's ~ $ {key} ~ $ {value} ~ g" "$ {FILE}"> "$ {TEMP_FILE}" ' – anubhava

+3

Можете ли вы написать [ (http://sscce.org/), который демонстрирует проблему? –

+0

Как выглядит ваш _array_? – devnull

ответ

2

Благодаря @BillKarwin для пятнистости сути проблемы: при каждой итерации цикла вытирает замены предыдущих итераций, потому что в результате одной ключа-значения замены пары каждый раз заменяет весь выходной файл.

Попробуйте следующее:

declare -a props 

# ... 

cp "$FILE" "$TEMP_FILE" 
for x in "${props[@]}"; do 
    IFS='=' read -r key value <<<"$x" 
    sed -i '' "s|${key}|${value}|g" "${TEMP_FILE}" 
done 
  • копии входного файла в выходной файл, а затем заменяет выходной файл в месте (используя sed «s -i вариант) в каждой итерации петля.
  • Я также упростил код для разбора каждой строки на ключ и значение, используя read.
  • Также обратите внимание, что я последовательно дублирует все ссылки на переменные.
  • @anubhava делает хорошее общий point: в зависимости от значений переменных может потребоваться другой разделитель регулярных выражений (в вашем случае: если ключи или значения содержат «|», вы не можете использовать '|' для разделите регулярные выражения).

Обновление: @BillKarwin делает хорошую точку: выполнения замены один за другим, в цикле, является неэффективным.

Вот один вкладыш, который позволяет избежать петель в целом:

sed -f <(awk -F'=' '{ if ($0) print "s/" $1 "/" substr($0, 1+length($1)) "/g" }' \ 
    "$FILE") "$FILE" > "$TEMP_FILE" 
  • Использует awk для создания всего набора команд для замещения sed (по одному на строку).
  • Затем передает результат посредством подстановки процесса в виде командного файла до sed с -f.
  • Обращается с футляром, в котором значения встроены = символы. правильно.
4
key='echo "${x}" | cut -d '=' -f 1 
value='echo "${x}" | cut -d '=' -f 2 

Использование бэк-тиков, а не одиночные кавычки , если вы хотите сделать подстановку команд.

key=`echo "${x}" | cut -d '=' -f 1` 
value=`echo "${x}" | cut -d '=' -f 2` 

также отметим, что, как вы цикла по серии key=value, вы каждый раз переписываете свой временный файл, используя только одну замену, применяемую к исходному файлу. Итак, после того, как цикл завершен, лучше всего вы можете надеяться, что будет применена только последняя подстановка.


Я также предлагаю не делать это в несколько проходов - сделать это путем передачи нескольких выражений СЭД:

for x in "${props[@]}" ; do 
    subst="$subst -e 's=$x=g'" 
done 
sed $subst "${FILE}" > "${TEMP_FILE}" 

Я использую трюк, с помощью = в качестве разделителя выражение подстановки sed, нам не нужно отделять ключ от значения. Команда становится просто:

sed -e 's=foo=1=g' -e 's=bar=2=g' "${FILE}" > "${TEMP_FILE}" 
+1

Я думаю, что это должно быть, факт, что он переписывается каждый раз. Любая идея, как я мог обойти это? –

+0

+1 для определения сути проблемы - работа предыдущих итераций цикла, которую уничтожают последующие; однако проблема обратного вызова больше не применяется. – mklement0

+0

Не заменяйте в петле: большое улучшение; небольшое предостережение: if * values ​​* have * embedded * '=' chars., команда 'sed' будет ломаться. В основном гипотетическая точка: создавая потенциально большую командную строку (вместо подачи команд через файл), вы рискуете столкнуться с макс. длина командной строки. – mklement0

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