linux
  • bash
  • recursion
  • sed
  • grep
  • 2013-04-10 2 views 28 likes 
    28

    Я получаюНайти и заменить строку во всех файлах рекурсивных с помощью Grep и СЭД

    sed: -e expression #1, char 22: unterminated `s' command 
    

    есть проблема на моем сценарии? Кроме того, "oldstring" имеет специальные символы

    #!bin/bash 
    oldstring='<script>"[oldscript]"</script>' 
    newstring='<script>"[newscript]"</script>' 
    grep -rl $oldstring /path/to/folder | xargs sed -i s/$oldstring/$newstring/g 
    
    +1

    квадратные скобки, возможно, должны быть экранированы. Также дважды укажите шаблон sed. – phs

    +3

    У вас также будет проблема с '/' в ваших шаблонах. Им следует избегать. Или вы можете использовать другой разделитель для команды '' '(например,' @ '). –

    ответ

    36

    Как сказал @Didier, вы можете изменить разделитель на что-то другое, чем /:

    grep -rl $oldstring /path/to/folder | xargs sed -i [email protected][email protected][email protected] 
    
    +5

    Вышеизложенное не получилось бы в SO много интересных способов, учитывая так много возможного содержимого oldstring или newstring. –

    +1

    @EdMorton, не могли бы вы привести пример того, как это происходит? Я знаю, что вы опубликовали традиционную форму работы ниже, но просто сказать, что это может не решить вопрос о том, как это сделать. Тогда я мог понять, почему я должен решить ваше решение. Это решение кажется гораздо более простым. Спасибо –

    +3

    Попробуйте вышесказанное с любым символом globing оболочки или @ в любой строковой переменной. Гвоздящие символы могут/будут соответствовать именам файлов в вашем каталоге, если не сегодня, то когда-нибудь в будущем, когда вы в последний раз ожидаете этого, и @ закончит вашу команду sed. Он также потерпит неудачу, если oldstring содержит пробелы в разных местах, не говоря уже о том, содержит ли строка строку символов новой строки. OP специально сказал, что «oldstring» имеет специальные символы, так что это большая голова, что любое из того, что я только что описал, и скорее всего произойдет. –

    3

    sed выражение должно быть цитируемый

    sed -i "s/$oldstring/$newstring/g" 
    
    4

    Ребята из GNU ДЕЙСТВИТЕЛЬНО перепутались, когда представили рекурсивный поиск файлов в grep. grep предназначен для поиска RE в файлах и печати соответствующей строки (g/re/p помните?) НЕ для поиска файлов. Есть отличный инструмент с очень очевидным именем для файлов FINDing. Что бы ни случилось с мантрой UNIX, чтобы сделать одно и сделать это хорошо?

    Во всяком случае, вот как вы могли бы сделать то, что вы хотите использовать традиционный UNIX подход (непроверенные):

    find /path/to/folder -type f -print | 
    while IFS= read -r file 
    do 
        awk -v old="$oldstring" -v new="$newstring" ' 
         BEGIN{ rlength = length(old) } 
         rstart = index($0,old) { $0 = substr($0,rstart-1) new substr($0,rstart+rlength) } 
         { print } 
        ' "$file" > tmp && 
        mv tmp "$file" 
    done 
    

    Не то, что с помощью AWK/индекс() вместо СЕПГ и Grep вам избежать необходимость избегайте всех метасимволов RE, которые могут появляться либо в вашей старой, либо в вашей новой строке, плюс выведите символ, который будет использоваться в качестве разделителя sed, который не может отображаться в ваших старых или новых строках, и что вам не нужно запускать grep поскольку замена будет происходить только для файлов, содержащих нужную строку. Сказав все это, если вы не хотите, чтобы временная метка файла изменилась, если вы не изменяете файл, просто выполните diff для tmp и исходного файла перед выполнением mv или введите fgrep -q до AWK.

    Предостережение. Вышеупомянутое не будет работать для имен файлов, содержащих символы новой строки. Если у вас есть, то дайте нам знать, и мы сможем показать вам, как с ними справиться.

    +2

    +1 Когда кто-то говорит об использовании 'sed' с' grep', есть отличная возможность использовать их только 'sed' или переключиться на' awk'. Кстати, если вы использовали '-print0' в своей находке и (в BASH) с помощью' -d \ 0', должны заботиться о именах файлов с новыми строками в них. –

    +0

    @DavidW. Правильно.И когда вы начинаете говорить об экранировании метасимволов RE, чтобы sed или grep не рассматривали их как таковые, вам нужно переключиться на awk/index() или fgrep, чтобы вы могли искать строки вместо RE. –

    +0

    @josten '-r' arg для' grep' является альтернативой использованию 'find', чтобы не использовать' awk'. Вы можете использовать 'awk' с' find + xargs' вместо 'grep + sed', и результат будет, как правило, более кратким и эффективным. Использование 'awk', безусловно, не приведет к созданию огромных свернутых однострочных линий. –

    9
    grep -rl $oldstring . | xargs sed -i "s/$oldstring/$newstring/g" 
    
    +0

    Таким образом, осложнение с этим, файлы с пробелами в их именах не будут подняты. Если у вас есть «/ files/File Two.txt», sed будет пытаться «/ files/File» и «Two.txt». – Captainlonate

    -1
    grep -rl SOSTITUTETHIS . | xargs sed -Ei 's/(.*)SOSTITUTETHIS(.*)/\1WITHTHIS\2/g' 
    
    Смежные вопросы