Insert character at specific location in a each line of the file

Hi All,

I am trying to write a shell script where it should insert character 'I' in 180th position of each line(except first and last line) of the file. Below is the script

for file in /home/test/bharat/*.RET
do
 # Process file
 echo "File Name=" $file
 #l_fileName="${file##*/}"
 l_fileName=`basename ${file}`_P
 mv $file $l_fileName
 echo "New File Name= " $l_fileName
 #Remove special chracters from the file
 sed 's/[!@#\$%^&*()]//g' $l_fileName>$file

 mv -f $l_fileName /home/test/bharat/archive
 
#Loop throguh all the lines in the file and insert I in 180 position 
COUNT=0
while read -r line; do
    COUNT=$(( $COUNT + 1 ))
	echo "line " $line
    echo "Inside the file line count: " $COUNT
	sed 's/./I/180' $line
done < $file

done

Somehow sed 's/./I/180' $line is not working properly. Please help to achieve this. and also i need to do this starting line 2 and should exclude last line.

Please help.

Thanks
Bharat

Hi,

Can you please try similar to below one ?Here i have simulated for 10th position in a file , excluding first and last line.

cat file
1234567890ABCD
1234567890XYZ
1234567890PQR
1234567890LMN
sed -e '1{n};$!s/./&a/10' file

Gives output:

Hope it helps.

1 Like

Hi greet,

When i try like this. I get an error:

sed: Function 1{n};$!s/./&I/10 cannot be parsed.

Below is the code i tried.

#Loop throguh all the lines in the file and insert I in 180 position 
COUNT=0
while read -r line; do
    COUNT=$(( $COUNT + 1 ))
	echo "line " $line
    echo "Inside the file line count: " $COUNT
	sed -e '1{n};$!s/./&I/10' line
done < $file

If i directly try this command on one single file it seems working. But my requirement is, it should happen for all the files in the directory..my files looks similar like below.

XXXXXXXXXXXXXXXXXXXXXXXXXXXXX       293800206774        XXXXXXXXXXXXXXXXX      
10210496781000100293800206774   %     30095                    15962835
10210496781000100293800206774   $     34099                    17054579
10210496781000100293800206774   #     999                      00000000

Thanks
Bharat

Please use code tags for code snippet and quote tags for text input/output.

Example i gave is for file and it refers to line such as first , exclude last line.

sed -e '1{n};$!s/./&I/10' line

is wrong here.

Is below are contents of file or file names ?

Here is what i can simulate with multiple files:

ls 
123.txt  456.txt  f1  f2
for file in *.txt
do
echo "File Name=" $file
sed '1{n};$!s/./&a/10' $file
done

Gives output :

Once you are sure that this is what you want, you can use in-place edit option

-i

to update in the file itself. Please note , you can not undo .

1 Like

Hi Greet,

Thanks for the quick reply.Sorry i am new to shell scripting.

Below is the content of the file

XXXXXXXXXXXXXXXXXXXXXXXXXXXXX 293800206774 XXXXXXXXXXXXXXXXX 
10210496781000100293800206774 % 30095 15962835
10210496781000100293800206774 $ 34099 17054579
10210496781000100293800206774 # 999 00000000

and i tried to use the same way as you suggested.

for file in /home/user/bharat/*.RET
do
echo "File Name=" $file
sed '1{n};$!s/./&a/10' $file
done

and its giving me the below error.

File Name= /home/user/bharat/CN01066C.RET
sed: Function 1{n};$!s/./&a/10 cannot be parsed.
File Name= /home/user/bharat/CN01067C.RET
sed: Function 1{n};$!s/./&a/10 cannot be parsed.

Thanks
Bharat

Hi Greet,

Again i tried with .txt files. But i get similar error.

I am attaching both the file used and shell script. Please help. Is it something to do with my unix version or something?

Thanks
Bharat

Hi,

It might be your version of sed / unix.

Tested in below versions and works fine:

sed --version
sed (GNU sed) 4.2.2
GNU sed version 4.1.5

can you please give a try as follows, if it helps?

sed '1n;$!s/./&a/10' file
1 Like

Hi greet,

Yeah. Now its working. Thanks a lot. You told me i can edit and save the file with the option -i. Could you please let me know how to do that.

Thanks a lot for your help. Below is the code and output.

echo "Program Begin" 
for file in *.txt
do
echo "File Name=" $file
sed '1n;$!s/./&a/10' $file
done
echo "Program End"

Output

Program Begin
File Name= abc.txt
abcdefghij klmnop  qrstuvwxyz
1234567891a0 11 12 13 14 15 16
ABCDEFGHIJaKLMNOPQRSTUVWZYZ
1234567891a0 11 12 13 14 15 16
12345678910 11 12 13 14 15 16
File Name= def.txt
abcdefghij klmnop  qrstuvwxyz
1234567891a0 11 12 13 14 15 16
ABCDEFGHIJaKLMNOPQRSTUVWZYZ
1234567891a0 11 12 13 14 15 16
12345678910 11 12 13 14 15 16
Program End

Good that it works with last change.

to make inplace/infile edit , use

sed -i '1n;$!s/./&a/10' $file

If you want to save a backup / copy of the file before modifying it, use

sed -i.bak '1n;$!s/./&a/10' $file

After execution of above command with -i.bak option, you have 2 files now.
1) before modification with .bak extension.
2) Modified file by sed command .

1 Like

Hi greet,

With option -i, its not working..i get below error.

$ sh test2.prog
Program Begin
File Name= abc.txt
sed: illegal option -- i
Usage:  sed [-n] [-u] Script [File ...]
        sed [-n] [-u] [-e Script] ... [-f Script_file] ... [File ...]
File Name= def.txt
sed: illegal option -- i
Usage:  sed [-n] [-u] Script [File ...]
        sed [-n] [-u] [-e Script] ... [-f Script_file] ... [File ...]
Program End

Thanks
Bharat

---------- Post updated at 03:34 PM ---------- Previous update was at 03:21 PM ----------

I tried it using another option. and it seems working. Thanks a lo for your help. Below is the code i tried.

for file in /home/user/bharat/*.RET
do
echo "File Name=" $file

l_fileName=`basename ${file}`_II

mv $file $l_fileName

echo "New File Name=" $file

sed  '1n;$!s/./&I/180' $l_fileName>$file

mv -f $l_fileName /home/user/bharat/archive

done

If we just stick with standard sed addressing constructs and do not depend on non-standard options, you could try something more like:

#!/bin/ksh
IAm=${0##*/}
tmpf="$IAm.$$"

trap 'rm -f "$tmpf"' EXIT

cd /home/user/bharat
for file in *.RET
do	printf 'File Name=%s\n' "$file"
	sed -e 1n -e '$n' -e 's/./I&/180' "$file" > "$tmpf" && cp "$tmpf" "$file"
done

Note that your description talks about INSERTING a character in the 180th position which I interpret to mean "insert a character before the 180th character on the existing line" while none of your sample input files have 180 characters in any line and all of the samples that have shown examples using character position 10 instead of 180 have been "appending a character after the 10th character" instead of "inserting a character before the 10th character. The above code attempts to "insert a character before the 180th character on lines 2 through n-1, inclusive, for a file that contains n lines.

The code samples you have shown unconditionally move the output produced by sed to the input file whether or not sed succeeded or failed. The above code only modifies the input file if the sed command completes successfully. Furthermore, it copies the updated file back to the original file (which preserves file permissions and hard links) while the moves used by your script will break any hard links to your input files and may destroy the contents of your input file if sed fails for any reason.

Hopefully, this will work better for you.

Note that it is always a good idea to tell us what operating system and shell you're using so the volunteers here trying to help you can avoid suggestions that won't work in your environment.

The previous script was written and tested using a Korn shell, but will work with any shell that is based on Bourne shell syntax and performs parameter expansions required by the POSIX standards (such as ash , bash , dash , ksh , and zsh ).

1 Like

Hi Don,

Thanks for your detailed explanation and solution. I will try this approach and update you.

Thanks
Bharat

Hi Don,

I tested this and works perfectly fine. I have one more requirement with the same operation. If 180th position already have character "I". i do not want to touch that file. I am not getting how to handle that with sed.

Any help is highly appreciated.

Thanks
Bharat

Don't touch that file or line?

1 Like

Hi Rudi,

Thanks for the reply.
Yes you are right. it should be line.

Thanks
Bharat

Try

sed -e 1n -e '$n' -e '/^.\{179\}I/ !s/./I&/180' file
1 Like

Thank you. I will try this and update you.

Thanks
Bharat

---------- Post updated at 12:05 PM ---------- Previous update was at 11:37 AM ----------

It works. Just fine. Thanks a lot.

for file in *.RET
do
echo "File Name in PROCESS Stage=" $file

#Insert character 'I' at 180th position if this chracter not exist
#sed -e 1n -e '$n' -e 's/./I&/180' "$file" > "$tmpf" && cp "$tmpf" "$file"
sed -e 1n -e '$n' -e '/^.\{179\}I/ !s/./I&/180' "$file" > "$tmpf" && cp "$tmpf" "$file"

done

With any POSIX-conforming sed you could also use:

sed -e 1n -e '$n' -e 's/^\(.\{179\}\)\([^I]\)/\1I\2/' "$file" > "$tmpf" && cp "$tmpf" "$file"

but RudiC's suggestion may be easier for some people to read.

1 Like

Hi Team,

My requirement is slightly changed and please help on the below.

Earlier i was trying insert a character(I) at 180th position of all the lines in the file except 1st and last line. Now i have little change in this requirement, I just need to replace whatever character in 180 the position to chracter "I".

I was using below code, But i am trying different options buts its not working.

sed -e 1n -e '$n' -e '/^.\{179\}I/ !s/./I&/180' "$file" > "$tmpf" && cp "$tmpf" "$file"

what code if i change in the above line,so i can make this work?

Thanks
Bharat

---------- Post updated at 10:59 AM ---------- Previous update was at 10:34 AM ----------

Hi Team,

I tried below code and it looks working fine. Please suggest of there any better way of doing it.

sed -e 1n -e '$n' -e 's/./I/180' "$file" > "$tmpf" && cp "$tmpf" "$file"

Many thanks.

Thanks
Bharat

Hi,

IMO, command you have tried looks good :b:

1 Like