Adding a new line to a growing paragraph using bash - linux

I'm trying to write a bash script that adds a new line to a continually growing paragraph of a file. For every time I run the script it should add a new line to that paragraph but instead it returns the entire content of the file.
Here's my code...
function registerServiceProvider {
# register service provider inside config/app.php
sed '/App\Providers\*::class,/a \ App\Providers\${repoName}${provider}::class,' ./config/app.php
}
registerServiceProvider

By default sed prints the resulting stream to stdout. If you have GNU sed you can use -i to modify the file in-place. With many BSD sed you can use -i but it requires an argument which will be the extension added to the backup file created.
If you want to stay more POSIXy you can redirect the output to a new file, then move that temp file over the old name (or redirect the output to make sure you don't change the permissions). Don't try to do it with redirection in one step though, because the first thing the shell will do is truncate the file, then you'll try to read it and it will be empty.
So, with GNU sed you can do:
sed -i -e '/App\Providers\*::class,/a \ App\Providers\${repoName}${provider}::class,' ./config/app.php
or with BSD (or GNU, the argument works but is optional with GNU)
sed -i .bak -e '/App\Providers\*::class,/a \ App\Providers\${repoName}${provider}::class,' ./config/app.php
or portably
sed '/App\Providers\*::class,/a \ App\Providers\${repoName}${provider}::class,' ./config/app.php > tmp_paragraph
cat tmp_paragraph > ./config/app.php
rm tmp_paragraph
If you want the repoName and provider variables to be shell variables that get expanded you need to put the sed script in double quotes. bash doesn't expand variables inside single quoted strings. So to take the GNU sed example you would change it to use double quotes like so:
sed -i -e "/App\\\\Providers\\\\*::class,/a \\ App\\\\Providers\\\\${repoName}${provider}::class," ./config/app.php
and note that we had to do plenty of extra escaping of the slashes, since bash will treat them as escape characters inside double quotes. We can use the single quotes to help with that as long as we put the variables outside it though (and note that I'm still going to double the quotes because I think you meant to do that to get actual back slashes in those spots)
sed -i -e '/App\\Providers\\*::class,/a \ App\\Providers\\'${repoName}${provider}'::class,' ./config/app.php

Related

How to replace a line (directory path) with a variable containing another line (new directory path) in a Linux file?

I have a file containing contents like:
aaaaaaaaaa
export ORACLE_HOME=/home/oracle/test/prod/db_1
bbbbbbbbbb
Now I want to replace the line of
export ORACLE_HOME=/home/oracle/test/prod/db_1
with something like below:
export ORACLE_HOME=/u01/app/oracle/product/11204/dbhome_1
I tried numerous ways found through Google like using "sed" or "awk" but neither one worked. I tried:
export D1="export ORACLE_HOME=/u01/app/oracle/product/11204/dbhome_1"
sed -i -e "s+export ORACLE_HOME=/home/oracle/test/prod/db_1+$D1+" file.lst
Note: as one Google search says, since the strings contains "/", so a different delimiter like "+" needs to be used.
Can you share with me the right command to do so?
sed -r 's~(ORACLE_HOME=).*~\1new/path/here~'
here ~ is used as the delimiter. If the new path is a bash variable, you can escape the quotes
sed -r 's~(ORACLE_HOME=).*~\1'$D1'~'
If you are still having trouble with the substitution, you can use this variation which will explicitly find the line containing export ORACLE_HOME before attempting the path substitution. The expression makes use of alternate delimiters for the substitution '|'.
To edit in place (Linux), you can use the '-i' option (and add '-i.bak' to make a backup of the original). If you are using a mac or other OS without the '-i' option available, use redirection to create a new file which you can copy over the current file.
sed -i '/^export\sORACLE_HOME/s|=.*$|=/u01/app/oracle/product/11204/dbhome_1|' \
yourfilename
or without '-i':
sed '/^export\sORACLE_HOME/s|=.*$|=/u01/app/oracle/product/11204/dbhome_1|' \
yourfilename > newfilename
cp yourfilename yourfilename.sav && mv -f newfilename yourfilename
(note: the '\' at the end of the sed command line is a simple line-continuation)
Using a Variable for Replacement
From your comment, if you want to use a variable instead of a hardcoded path for the replacement string, then simply replace the single-quotes with double-quotes and include the variable as the replacement string. For example:
npath=/u01/app/oracle/product/11204/dbhome_1
sed -i "/^export\sORACLE_HOME/s|=.*$|=$npath|" dat/opath.txt

Trying to run sed command using as pattern lines from other file [duplicate]

I am trying to change the values in a text file using sed in a Bash script with the line,
sed 's/draw($prev_number;n_)/draw($number;n_)/g' file.txt > tmp
This will be in a for loop. Why is it not working?
Variables inside ' don't get substituted in Bash. To get string substitution (or interpolation, if you're familiar with Perl) you would need to change it to use double quotes " instead of the single quotes:
# Enclose the entire expression in double quotes
$ sed "s/draw($prev_number;n_)/draw($number;n_)/g" file.txt > tmp
# Or, concatenate strings with only variables inside double quotes
# This would restrict expansion to the relevant portion
# and prevent accidental expansion for !, backticks, etc.
$ sed 's/draw('"$prev_number"';n_)/draw('"$number"';n_)/g' file.txt > tmp
# A variable cannot contain arbitrary characters
# See link in the further reading section for details
$ a='foo
bar'
$ echo 'baz' | sed 's/baz/'"$a"'/g'
sed: -e expression #1, char 9: unterminated `s' command
Further Reading:
Difference between single and double quotes in Bash
Is it possible to escape regex metacharacters reliably with sed
Using different delimiters for sed substitute command
Unless you need it in a different file you can use the -i flag to change the file in place
Variables within single quotes are not expanded, but within double quotes they are. Use double quotes in this case.
sed "s/draw($prev_number;n_)/draw($number;n_)/g" file.txt > tmp
You could also make it work with eval, but don’t do that!!
This may help:
sed "s/draw($prev_number;n_)/draw($number;n_)/g"
You can use variables like below. Like here, I wanted to replace hostname i.e., a system variable in the file. I am looking for string look.me and replacing that whole line with look.me=<system_name>
sed -i "s/.*look.me.*/look.me=`hostname`/"
You can also store your system value in another variable and can use that variable for substitution.
host_var=`hostname`
sed -i "s/.*look.me.*/look.me=$host_var/"
Input file:
look.me=demonic
Output of file (assuming my system name is prod-cfm-frontend-1-usa-central-1):
look.me=prod-cfm-frontend-1-usa-central-1
I needed to input github tags from my release within github actions. So that on release it will automatically package up and push code to artifactory.
Here is how I did it. :)
- name: Invoke build
run: |
# Gets the Tag number from the release
TAGNUMBER=$(echo $GITHUB_REF | cut -d / -f 3)
# Setups a string to be used by sed
FINDANDREPLACE='s/${GITHUBACTIONSTAG}/'$(echo $TAGNUMBER)/
# Updates the setup.cfg file within version number
sed -i $FINDANDREPLACE setup.cfg
# Installs prerequisites and pushes
pip install -r requirements-dev.txt
invoke build
Retrospectively I wish I did this in python with tests. However it was fun todo some bash.
Another variant, using printf:
SED_EXPR="$(printf -- 's/draw(%s;n_)/draw(%s;n_)/g' $prev_number $number)"
sed "${SED_EXPR}" file.txt
or in one line:
sed "$(printf -- 's/draw(%s;n_)/draw(%s;n_)/g' $prev_number $number)" file.txt
Using printf to build the replacement expression should be safe against all kinds of weird things, which is why I like this variant.

sed and the odyssey of escaping a bash variable

Having
DEST_PATH='/var/www/clones'
site='xyz.com'
sed -i -e "s/\$log_path\s=\s'\(.*\)'/\$log_path = '$DEST_PATH\/$site\/logs'/" $DEST_PATH/$site/configuration.php
The problem is the forward slashes in first variable, because this is what is being processed and returns error:
sed -i -e "s/\$log_path\s=\s'\(.*\)'/\$log_path = '/var/www/clones\/xyz.com\/logs'/" configuration.php
When this is what actually should be run:
sed -i -e "s/\$log_path\s=\s'\(.*\)'/\$log_path = '\/var\/www\/clones\/xyz.com\/logs'/" configuration.php
So I know, I could replace all the / inside $DEST_PATH, and run the sed again, but I was wondering if you know or can think of any other/better way of doing so. Ideally, maybe having sed automatically escape the '$DEST_PATH/$site/logs' if possible.
Are you using a modern enough version of sed (e.g., GNU sed)? Then you are not required to use / to separate pattern and substitution. Any character will do.
E.g., you can use
s,pattern,substitution,
instead of
s/pattern/substitution/

How to remove line containing a specific string from file?

I have a file BookDB.txt which stores information in the following manner :
C++ for dummies:Jared:10.67:4:5
Java for dummies:David:10.45:3:6
PHP for dummies:Sarah:10.47:2:7
Assuming that during runtime, the scipt asks the user for the title he wants to delete. This is then stored in the TITLE variable. How do I then delete the line containing the string in question? I've tried the following command but to no avail :
sed '/$TITLE/' BookDB.txt >> /dev/null
You can for example do:
$ title="C++ for dummies"
$ sed -i "/$title/d" a
$ cat a
**Java for dummies**:David:10.45:3:6
**PHP for dummies**:Sarah:10.47:2:7
Note few things:
Double quotes in sed are needed to have you variable expanded. Otherwise, it will look for the fixed string "$title".
With -i you make in-place replacement, so that your file gets updated once sed has performed.
d is the way to indicate sed that you want to delete such matching line.
Your command should be,
sed "/$TITLE/d" file
To save the changes, you need to add -i inline edit parameter.
sed -i "/$TITLE/d" file
For variable expansion in sed, you need to put the code inside double quotes.

How to search and replace text in a file from a shell script?

I'm trying to write a shell script that does a search and replace inside a configuration file upon start-up.
The string we're trying to replace is:
include /etc/nginx/https.include;
and we want to replace it with a commented version:
#include /etc/nginx/https.include;
The file that contains the string that we want to replace is:
/etc/nginx/app-servers.include
I'm not a Linux guru and can't seem to find the command to do this.
perl -p -i -e 's%^(include /etc/nginx/https.include;)$%#$1%' /etc/nginx/ap-servers.include
If the line might not end in the ;, use instead:
perl -p -i -e 's%^(include /etc/nginx/https.include;.*)$%#$1%' /etc/nginx/ap-servers.include
If you want to preserve the original file, add a backup extension after -i:
perl -p -i.bak -e 's%^(include /etc/nginx/https.include;)$%#$1%' /etc/nginx/ap-servers.include
Now, explaining. The -p flag means replace in-place. All lines of the file will be fed to the expression, and the result will be used as replacement. The -i flag indicates the extension of the backup file. By using it without anything, you prevent generation of backups. The -e tells Perl to get the following parameter as an expression to be executed.
Now, the expression is s%something%other%. I use % instead of the more traditional / to avoid having to escape the slashes of the path. I use parenthesis in the expression and $1 in the substituted expression for safety -- if you change one, the other will follow. Thus, %#$1% is actually the second % of s, followed by the desired #, $1 indicating the pattern inside parenthesis, and the last % of s.
HTH. HAND.
sed -i 's/foo/bar/g' config.txt
This replaces all instances of foo (case insensitive) with bar in the file config.txt
Check out sed:
sed -i -r 's|^(include /etc/nginx/https.include;)$|#\1|' /etc/nginx/app-servers.include
-i means do the substitution in-place and -r means to use extended regular expressions.
cd pathname
for y in `ls *`;
do sed "s/ABCD/DCBA/g" $y > temp; mv temp $y;
done
This script shold replace string ABCD to DCBA in all the files in pathname

Resources