简体   繁体   中英

Replace the same string several times with different strings in a file using bash

I have a file with this content

  import os
  import sys

  sys.path.append('/home/user/dj/project/')
  sys.path.append('/home/user/dj/')

  os.environ.setdefault("DJANGO_SETTINGS_MODULE", "proj.settings")

  import django.core.handlers.wsgi
  application = django.core.handlers.wsgi.WSGIHandler()

/home/user/dj/proj/ and /home/user/dj/ could be other, unknown values.

I have a bash script to do an installation, and in there I want to execute something to change those lines to this

  import os
  import sys

  sys.path.append('/var/django/proj/')
  sys.path.append('/var/django/')

  os.environ.setdefault("DJANGO_SETTINGS_MODULE", "proj.settings")

  import django.core.handlers.wsgi
  application = django.core.handlers.wsgi.WSGIHandler()

I tried with sed but I had troubles with greediness in regex.

I tried with perl -pi -es/str1/str2/ but I had troubles because perl repaces all occurences.

EDIT: To clarify, I want to replace only the values inside the single quotes. ie:

sys.path.append('foo') with sys.path.append('what I want') and

sys.path.append('bar') with sys.path.append('the second thing I want')

and bar could be different or equal to foo

As a basis for your solution:

 replStr="/var/django"
 echo "sys.path.append('/home/user/dj/project/')" \
| sed "s@sys.path.append('[^'][^']*[']@sys.path.append('${replStr}'@"

output

sys.path.append('/var/django')

The trick to getting a non-greedy solution, is to say "[^']" (any char not a sngl-quote). Adding the second "[^']*" (and the star), make the whole setting say, "at least 1 char that is not a single-quote". Then you add a single-quote (I use the char-class container to make it more visible, it may not be needed).

When a search target is known, I prefer just to match it, and then type it out again in my replacment string, rather than try to capture the value inside of ()s and reference with \1. again, just that it makes what is happening a little more obvious to a maintenance coder.

I hope this helps

sed 's@home/user/[^/]*@var/django@' file

is it what you are looking for?

it will replace /home/user/any_user to /var/django

I ran this on the bash command line against a carbon copy of your code ( filename ) and it worked a treat;

sed s/sys\.path\.append\(\'.*\'\)/sys\.path\.append\(\'\\/var\\/django\\/proj\\/\'\)/ filename

There's a lot of escaping but works a treat if you're wanting to affect all sys.path.append() calls in your programs. Obviously, it's easy to tweak to work with other function/method calls.

If you want a bash script that you can run against any program to change the string passed into any given function then you could use this;

#!/bin/bash

# Usage:  replacer.bash funcname repstring inputfile
#         funcname - function/method to affect
#         repstring - replacement string that you want passed into the function/method
#         inputfile - program/script to process

function main
{
    fun=$1
    shift
    text=$1
    shift

    sed "s@\\($fun\\)(\'.*\')@\\1\(\'$text\'\)@" $1
}

main $* 

Example;

replacer.bash sys.path.append /var/django/proj/ myprog > myprog.new

I finally used this

sed -i "1,/sys.path.append/ {/sys.path.append/i sys.path.append('$HOMEDIR/')\nsys.path.append('/home/$SYS_USER/')
}" $HOMEDIR/wsgi.py

with that carriage return before the }

is the only thing that worked for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM