2013-12-06 4 views
5

Я пытаюсь написать сценарий оболочки, который заменит любые символы/строки, которые я выбираю, используя sed. Моя первая попытка работала, за исключением специальных символов. Я пытаюсь использовать sed для исправления специальных символов, чтобы их тоже искали или заменяли. Я решил упростить сценарий для тестирования, и просто иметь дело с одним оскорбительным персонажем. Однако у меня все еще есть проблемы.Замена специальных символов в сценарии оболочки с помощью sed

Edited Script

#! /bin/sh 
oldString=$1 
newString=$2 
file=$3 

oldStringFixed=$(echo "$oldString" | sed 's/\\/\\\\/g') 
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\[/\\\[/g') 
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\]/\\\]/g') 
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\^/\\\^/g') 
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\*/\\\*/g') 
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\+/\\\+/g') 
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\./\\\./g') 
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\$/\\\$/g') 
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\-/\\\-/g') 

sed -e "s/$oldStringFixed/$newString/g" "$file" > newfile.updated 
mv newfile.updated "$file"#! /bin/sh 

В случае, если это не ясно, я пытаюсь искать через oldString для [характера, и заменить его экранирование и присвоить результаты oldStringFixed (мне нужно backticks для этого?). Нижние две строки - это слегка измененные версии моего исходного сценария, которые, я считаю, работают правильно.

Когда я вторят фиксированную строку, ничего не отображается, и SED выдает ошибку

sed: can't read [: No such file or directory 

Может кто-нибудь объяснить, что случилось с моей первой SED линии?

EDIT:

Благодаря Jite, скрипт работает лучше. Однако у меня все еще возникает проблема с заменой одинарных кавычек пробелами, т. Е. '*'. Новая версия выше.

+0

есть намного больше, чем specias символ «[», как. \ * +? для OldString и \ &/для newString – NeronLeVelu

+0

Довольно похоже на вопрос [this] (http://stackoverflow.com/questions/20427289/quoting-special-characters-with-sed/20427706). – devnull

ответ

1

Изменение:

oldStringFixed= `sed 's/\[/\[/g' "$oldString"\` 

к:

oldStringFixed=$(echo "$oldString" | sed 's/\[/\\\[/g') 

Задача 1: Space после =, это не допускается при назначении переменных оболочки.

Задача 2: sed ожидает файл как вход, а не строку. Вы можете передать его, как мое решение.

Проблема 3: Вы должны избежать обратной косой черты первого \\, то вам нужно, чтобы избежать вашего полукокса \[, общим объемом \\\[ :)

Side Примечание: Я изменил `` до $(), так как последняя является рекомендуемым праксис (из-за гнездования, другая тема).

+0

Спасибо за помощь. Ваши изменения отлично работают, и я добавил дополнительные команды sed для работы с другими персонажами проблем. Однако, когда я пытаюсь заменить один кавычек символом пробелом, таким как '*', вывод неверен. В любом случае это может быть исправлено? – user3074091

+0

Все может быть исправлено. Честно говоря, для этого случая я бы написал файл 'sed.script', который содержит все команды, которые должны быть выполнены, по одному в каждой строке, а затем использовать' sed -f sed.script' только один раз, вместо того, чтобы переустанавливать 'sed' много раз. Это также означает, что вам не нужно скрывать скрипт от оболочки - это облегчает жизнь. –

+0

@ user3074091 У меня нет вашего вопроса. Пожалуйста, обновите свой вопрос с примера ввода и того, что вы ожидаете, надеюсь, мы сможем найти ответ. – Jite

3

Я предлагаю два улучшения:

  1. Не складывайте вызовы sed, как вы, вместо того, чтобы упаковать их все в одной функции, так как escape_string ниже.

  2. Вы можете использовать причудливый разделитель для команды замены sed, чтобы избежать проблем, связанных с /, являющимся частью вовлеченных строк.

С учетом этих изменений, ваш сценарий выглядит следующим образом:

#! /bin/sh 
oldString="$1" 
newString="$2" 
file="$3" 

escape_string() 
{ 
    printf '%s' "$1" | sed -e 's/[][\\^*+.$-]/\\\1/g' 
} 

fancyDelim=$(printf '\001') 

oldStringFixed=$(escape_string "$oldString") 
sed -e "s$fancyDelim$oldStringFixed$fancyDelim$newString${fancyDelim}g" "$file" \ 
    > newfile.updated 
mv newfile.updated "$file" 
+1

Вы можете легко обобщить на 's/[] [\\^* +. $ -]/\\\ 1/g' (и я не уверен, почему вы хотите включить дефис, поэтому я предлагаю вам принять его вне). – tripleee

+0

Отлично, я добавил ваши изменения! –

+0

Это не работает для меня, я получаю выражение sed: -e # 1, char 21: неверная ссылка \ 1 на 's 'команда RHS" –

0

Для меня это был просто кошмар пытается получить СЕПГ, чтобы сделать это в общем случае.Я сдался и написал короткий код Python для замены СЭД:

#!/usr/bin/python 
# replace.py 
import sys 

# Replace string in a file (in place) 
match=sys.argv[1] 
replace=sys.argv[2] 
filename=sys.argv[3] 

print "Replacing strings in",filename 

with open(filename,"r") as f: 
    data = f.read().replace(match,replace) 

with open(filename,"w") as f: 
    f.write(data) 

, который затем может быть использован как:

#!/bin/bash 
orig='<somethinghorrible>' 
out='<replacement>' 
python replace.py "$orig" "$out" myfile.txt 
Смежные вопросы