Shell Scripting , need to search and replace a string in AIX

Hi Guys,

I need to search and replace a string in AIX using variables and should be case insensitive.

I am able to search and replace using below command but its not working as case insensitive.

cat abc.txt | sed -e 's/$a/$b/g'  >  abc.txt

But i need to perform this with case insensitive , it should ignore upper/lower case.

I have tried below code but its working only in Linux , not in AIX , any help??

cat abc.txt | sed -e 's/$a/$b/gI'  >  abc.txt

===============================

Example :- I have a variable value called "hello" in $a

Below the the file abc.txt .

HELLO , My name is mohit.

Now i need to search for $a i.e "hello" in abc.txt and replace it with another variable say $2 , whose value is "hi"

Sample O/P

hi , My name is mohit.

This is VERY disturbing. The command:

cat abc.txt | sed -e 's/$a/$b/g'  >  abc.txt

will NOT do what you said it will do on any Linux system, on any UNIX system (including AIX), nor on any BSD system.

You haven't bothered to tell us what shell you're using, but with any of the common shells available on any of the systems listed above that I am aware of, the above command will do the same thing on every one of those systems: truncate abc.txt so that it will be an empty file.

If you weren't redirecting output to your input file (thereby destroying your input file before cat and sed ever see it), you are still using single quotes that cause $a and $b to be treated as literal strings instead of having the shell expand them.

If you want to run a script on an AIX system and on a Linux system and have it behave the same way on both of those systems, you cannot use options that are only available on one of those systems.

If you expect us to help you, you need to show us the actual results that you are getting on both systems. I.e., show us:

  • the contents of your file before you run your command(s) on your Linux system (in CODE tags),
  • the contents of the variables you are using in your commands on your Linux system (in CODE tags),
  • any diagnostic messages printed while running your command(s) on your Linux system (in CODE tags),
  • the contents of your file after you run your command(s) on your Linux system (in CODE tags),
  • the contents of your file before you run your command(s) on your AIX system (in CODE tags),
  • the contents of the variables you are using in your commands on your AIX system (in CODE tags),
  • any diagnostic messages printed while running your command(s) on your AIX system (in CODE tags), and
  • the contents of your file after you run your command(s) on your AIX system (in CODE tags),

and tell us:

  • what Linux distribution you're using (including version number),
  • what shell you're using on your Linux system (including version number),
  • what AIX version you're using, and
  • what shell you're using on your AIX system.
Moderator comments were removed during original forum migration.

On AIX it is most probably a ksh88, which is the systems default shell. It is rarely changed to anything else.

For the rest of your objections: +1 from me!

bakunin

If the OP's original script had been developed on AIX, that would be my assumption as well. In this case, however, we seem to have a script that was developed on some unnamed Linux distribution (where bash or ash is much more common as the default shell). Therefore, I want the OP to explicitly state which shell is being used on both systems. (And, this is especially true if there is a shell on the Linux system that performs variable expansions in single-quoted strings!)

Hi Guys ,
Thanks for all the details , and sorry for not being too descriptive about my problem.

Let me try to explain again with proper details.

I am writing a shell script in bash in which i want to search and replace a particular string at particular line using a variable in AIX, and i can accomplish that using below command.

For example :- I have a file with name abc.txt with below 2 lines

Hello , My name is MOHIT
I am learning shell script

Now ,i have some variables in my script that have following values

line_number=1
current_value=MOHIT
new_value=Ankit

code :

cat abc.txt | sed -e $line_number"s/$current_value/$new_value/g" > abc.txt

It works perfectly and gives me the O/P as

Hello , My name is Ankit
I am learning shell script

But i want to ignore case sensitiveness , again by example of a file , abc.txt , now i have mohit written in lower case

Hello , My name is mohit
I am learning shell script

Again , i have some variables in my script that have following values

line_number=1
current_value=MOHIT
new_value=Ankit

code :

cat abc.txt | sed -e $line_number"s/$current_value/$new_value/g" > abc.txt

This is not working , please suggest.

Note: I have tried using I at the end, its working for other linux distributions , but not on my AIX systems.

code:

cat abc.txt | sed -e $line_number"s/$current_value/$new_value/gI" > abc.txt

AIX :- OS version
7100-03-02-1412

Thanks in advance!

As I said before, using any of the following commands:

cat abc.txt > abc.txt
cat abc.txt | sed "any sed arguments" > abc.txt
sed "any sed arguments" abc.txt > abc.txt

will result in abc.txt being a file of size 0, containing absolutely no characters. So, the code that you say is working on your Linux systems cannot possibly do what you say it is doing. The following should come close to what you said you want on a Linux distribution and on an AIX system:

#!/bin/bash
IAm=${0##*/}

file="abc.txt"
tmpfile="$IAm".$$

trap 'rm -rf "$tmpfile"' EXIT

line_number=1
current_value=MOHIT
new_value=Ankit

# Function to convert a string to a BRE that will match a case-insensitive
# version of that string.
# Usage: string2CIBRE "string"
string2CIBRE() {
	awk -v s="$1" '
		BEGIN {	for(i = 1; i <= length(s); i++)
			printf("%s", ((L = substr(s, i, 1)) ~ /[[:alpha:]]/) ? \
			    "[" tolower(L) toupper(L) "]" : L)
		}
	'
}

printf 'Contents of "%s" before sed:\n' "$file"
cat "$file"
sed "${line_number}s/$(string2CIBRE "$current_value")/$new_value/g" "$file" > "$tmpfile"  &&
	cp "$tmpfile" "$file"
printf '**********\nContents of "%s" after sed:\n' "$file"
cat "$file"

If abc.txt contains the following before you run the above script:

Hello , My name is Mohit, all lowercase: mohit, all uppercase: MOHIT
I am learning shell script
Hello , My name is Mohit, all lowercase: mohit, all uppercase: MOHIT
I am learning shell script

the output from the above script will be:

Contents of "abc.txt" before sed:
Hello , My name is Mohit, all lowercase: mohit, all uppercase: MOHIT
I am learning shell script
Hello , My name is Mohit, all lowercase: mohit, all uppercase: MOHIT
I am learning shell script
**********
Contents of "abc.txt" after sed:
Hello , My name is Ankit, all lowercase: Ankit, all uppercase: Ankit
I am learning shell script
Hello , My name is Mohit, all lowercase: mohit, all uppercase: MOHIT
I am learning shell script

and, as indicated by the output, the contents of abc.txt after running the script will be:

Hello , My name is Ankit, all lowercase: Ankit, all uppercase: Ankit
I am learning shell script
Hello , My name is Mohit, all lowercase: mohit, all uppercase: MOHIT
I am learning shell script

In addition to working with bash , this should also work with a 1988 or a 1993 version of the Korn shell ( ksh ) or any other shell that performs basic POSIX shell required parameter expansions.

Don Cragun is - as always - right on the money: what you showed us will not work at all (at least not on any Linux- or UNIX-system that i know of) in the presented way.

Here is another take, based on sed in a subfunction. Note that it will have some limitations regarding escaped strings because the shell may eat away some of the escapes during parsing (but, honestly, i found the parsing of the input string solely with shell expansion to be neat - admittedly, it is a showoff):

#! /usr/bin/ksh

function pReplaceCaseInsensitive
{
typeset     chInRegex="$1"
typeset     chReplacement="$2"
typeset     fIn="$3"
typeset     chOutRegex=""
typeset     chBuf=""
typeset -u chUpChar=""
typeset -l chLowChar=""
typeset    chInline=""

while [ -n "${chInRegex}" ] ; do
     chBuf="${chInRegex##?}"                  # chop off first character
     chLowChar="${chInRegex??${chBuf}}"       # get first char, invert to lower
     if print - "$chLowChar" | grep -q '[abcdefghijklmnopqrstuvwxyz]' ; then
          chUpChar="$chLowChar"
          chOutRegex="${chOutRegex}[${chLowChar}${chUpChar}]"
     else
          chOutRegex="${chOutRegex}${chInRegex%%${chBuf}}"
     fi
     chInRegex="$chBuf"
done

if [ -n "$fIn" ] ; then                       # deal with input from a file if specified
     if [ -r "$fIn" ] ; then
          sed 's/'"$chOutRegex"'/'"$chReplacement"'/g' "$fIn"
     else
          print -u2 "file $fIn is not readable or does not exist."
          return 1
     fi
else                                        # deal with input from stdin otherwise
     while read chInLine ; do
          print - "$chInLine" | sed 's/'"$chOutRegex"'/'"$chReplacement"'/g'
     done
fi

return 0
}

# main()

# first variant: use in a pipeline:
print - "Willy willy WIlLy test" | pReplaceCaseInsensitive 'willy' "Text"
# produces: "Text Text Text test"
print - "Willy willy WIlLy test" | pReplaceCaseInsensitive 'willy *' "Text"
# produces: "TextTextTexttest" (space gets eaten by the regexp " *")

# second variant: use with a file
pReplaceCaseInsensitive 'willy' "TEST" myfile

exit 0

Contents of myfile:

# cat myfile
Willy
willY
WiLlY
bla

Results of the second call to pReplaceCaseInsensitive():

TEST
TEST
TEST
bla

I hope this helps.

bakunin

Thanks for the response. I will try this thing.

I just have one more issue related to find and replace with sed.

Lets say i have a file abc.txt like below

nas1:/var/core/test        /test
nas1:/var/core/test/test2  /test1

Now i just need to search and replace only "nas1:/var/core/test" which i have in form of variable. It should not touch "nas1:/var/core/test/test2".

Any help on this , thanks in advance !

Do you have a GNU sed available?

sed 's#nas1:/var/core/test #\U&#' file
NAS1:/VAR/CORE/TEST        /test
nas1:/var/core/test/test2  /test1