Replace keywords in an argument - bash scripting - bash

I have a file that is taking in a path as an argument:
./<filename> /path/to/file...
What I want to do is replace the /path/to/... part with /another/file/...
I was trying to sed the argument in the following manner:
CUR_PATH=$1
OLD_PATH="\/path\/to\/"
NEW_PATH="\/another\/file\/"
sed "s/$OLD_PATH/$NEW_PATH/" $CUR_PATH
But this isn't working because of the fact that sed is trying to actually modify the file at CUR_PATH and not the actual statement of CUR_PATH. How do I fix this? Thanks.

Another possibility is to use a here string:
CUR_PATH=$1
OLD_PATH="/path/to/"
NEW_PATH="/another/file/"
sed "s|$OLD_PATH|$NEW_PATH|" <<< $CUR_PATH
Also note that you can vary the delimiters for the substitution in sed, so that you don't have to escape the slashes in your path variables.

You don't need sed. bash a built-in substitution for variables. You can use:
NEW_PATH=${OLD_PATH/\/path\/to\//\/another\/file\/}
Note the backslashing of the /, because the expression is ${variable/old/new}.

You can use bash's substitution as Diego suggests, but for this particular case it is probably cleaner to do:
NEW_PATH="/another/file/${OLD_PATH##*/}"
which will replace the entire leading path of OLD_PATH with the string "/another/file/". Note that the double quotes are only necessary if OLD_PATH may contain whitespace.
If you do want to use sed, you can simply echo OLD_PATH into a pipe. And, when using sed for manipulating filenames, it is convenient to use a different separator. For example:
NEW_PATH=$( echo $OLD_PATH | sed s#/path/to/my#/another/file# )

Related

replace entire line in file with new line given arguments line number and replacement string with special characters

I have 2 bash script variables defined:
THELINENUMBER="14" # an arbitrary line number, comes from a separate command
NEWLINE="a line/ with# special! characters<" # arbitrary line with special characters, comes from separate command
I need to use the line number ${THELINENUMBER} to replace a line in a file called after.txt with ${NEWLINE}.
How do I do that?
These are some examples I have tried:
sed -i '${THELINENUMBER}s#.*#"/"${NEWLINE}"/"' after.txt
sed -i "${THELINENUMBER}s#.*#"/"${NEWLINE}"/"" after.txt
sed -i "${THELINENUMBER}s/.*/'${NEWLINE}'" after.txt
sed -i '${THELINENUMBER}s,.*,${NEWLINE}' after.txt
I am told that the delimitter is usually a /, but those are present in my line replacement variable, so I can't use those. I tried with # and , but the desired behavior did not change. I am also told that " and ' are supposed to be used to turn off escaping in text (use literal string), but I have not been able to get that to work either. How do I pass in a string parameter into sed that has special characters? I am wondering if I should pass the variable ${NEWLINE} into another built-in function call to add escape characters or something before passing it into sed. Is sed the right tool for the job? I did not find much helpful information looking at the CLI manpages. I use Ubuntu 18.04.
I have referred to these sources in my internet search:
https://stackoverflow.com/questions/11145270/how-to-replace-an-entire-line-in-a-text-file-by-line-number
https://askubuntu.com/questions/76808/how-do-i-use-variables-in-a-sed-command
https://stackoverflow.com/questions/37372047/find-a-line-with-a-string-and-replace-entire-line-with-another-line
Use the c (change) command.
By the way, the naming convention for regular shell variables is NOT ALLCAPS, as that may result in accidental collisions with special variables like PATH.
sed "$linenumber c\\
$newline" file
Try
sed -i "${THELINENUMBER}s#.*#${NEWLINE}#" after.txt
this works because:
You require " enclosing the entire sed command instead of backtick so that the variables are expanded
No other quotes or backticks are needed to escape " in the variables as there aren't any: there are no literal (escaped) quotes inside the variables
An alternate separator (such as #) is required due to the / inside the NEWLINE variable.

Replace Double quotes with space

this is perhaps one of the most discussed topics here. I tried almost all the commands and other tweaks found here, but something doesn't seems to be doing well.
i would want to replace all the double quotes in my file with whitespace/blank
I'm seeing the below error when i tried to execute this command.
sed "s/"/ \''/g' x_orbit.txt > new.tx
sed: -e expression #1, char 3: unterminated `s' command
You're close. Just use single quotes, so the shell doesn't try to expand the metacharacters in your sed command:
sed 's/"/ /g' x_orbit.txt > new.txt
You could try tr for example:
tr '"' ' ' < x_orbit.txt > new.txt
The script you provided:
sed "s/"/ \''/g' x_orbit.txt > new.tx
means:
sed # invoke sed to execute the following script:
" # enclose the script in double quotes rather than single so the shell can
# interpret it (e.g. to expand variables like $HOME) before sed gets to
# interpret the result of that expansion
s/ # replace what follows until the next /
" # exit the double quotes so the shell can now not only expand variables
# but can now do globbing and file name expansion on wildcards like foo*
/ # end the definition of the regexp you want to replace so it is null since
# after the shell expansion there was no text for sed to read between
# this / and the previous one (the 2 regexp delimiters)
\' # provide a blank then an escaped single quote for the shell to interpret for some reason
'/g' # enclose the /g in single quotes as all scripts should be quoted by default.
That is so far off the correct syntax it's kinda shocking which is why I dissected it above to try to help you understand what you wrote so you'll see why it doesn't work. Where did you get the idea to write it that way (or to put it another way - what did you think each character in that script meant? I'm asking as it indicates a fundamental misunderstanding of how quoting and escaping works in shell so it'd be good if we could help correct that misunderstanding rather than just correct that script.
When you use any script or string in shell, simply always enclose it in single quotes:
sed 'script' file
var='string'
unless you NEED to use double quotes to let a variable expand and then use double quotes unless you NEED to use no quotes to let globbing and file name expansion happen.
An awk version:
awk '{gsub(/"/," ")}1' file
gsub is used for the replace
1 is always true, so line is printed

replace file path name from multiple file using sed

I want to replace <lexicon uri="file://C:/image/png/grammars/custom/image-custom.lex?SWI.type=backup"/><lexicon uri="file://C:/image/jpg/grammars/custom/image-dot-custom.lex?SWI.type=backup"/> with null in multiple files.
The code is given below.
sed -i s|<lexicon uri="file://C:/image/png/grammars/custom/image-custom.lex?SWI.type=backup"/><lexicon uri="file://C:/image/jpg/grammars/custom/image-dot-custom.lex?SWI.type=backup"/>||g *
Here I am getting this error:
< was unexpected at this time.
Please clarify for me what is not working here.
Could you please try following and let me know if this helps you. By using # as sed's separator you need not to escape / in it only need to escape ., ? not to take their special meaning
sed -E 's#<lexicon uri="file://C:/image/png/grammars/custom/image-custom\.lex\?SWI\.type=backup"/><lexicon uri="file://C:/image/jpg/grammars/custom/image-dot-custom\.lex\?SWI\.type=backup"/>##' Input_file
Tested it with:
sed --version
GNU sed version 4.2.1
works with #
sed -i -e 's#<lexicon uri="file://C:/image/png/grammars/custom/image-custom.lex?SWI.type=backup"/><lexicon uri="file://C:/image/jpg/grammars/custom/image-dot-custom.lex?SWI.type=backup"/>##g' test.txt
The pattern contains shell metacharacters, which need to be quoted or escaped. Usually, in Bash, you should use single quotes around strings, unless you need the shell to interpolate variables and command substitutions and interpret backslash sequences (in which case use double quotes) or to also perform whitespace tokenization and wildcard expansion (in which case use no quotes). See also When to wrap quotes around a shell variable?
sed -i 's|<lexicon uri="file://C:/image/png/grammars/custom/image-custom.lex?SWI.type=backup"/><lexicon uri="file://C:/image/jpg/grammars/custom/image-dot-custom.lex?SWI.type=backup"/>||' *
I also took out the g flag, which only makes sense if you expect multiple matches within a single line. (Perhaps you do after all, in which case obviously put it back.)

Bash remove every occurrence after first in string

I'm trying to remove everything after a specific_string in a path string in Bash. I've tried using sed to no avail so far.
variable="specific_string"
input_string="/path/to/some/specific_string/specific_string.something/specific_string.something-else"
output=$(sed 's/$variable//' $input_string)
Output should be "/path/to/some/specific_string/"
Would be better if I didn't have to use commands such as sed!
The Problems
There are many problems
Variables are not evaluated inside single quotes. 's/$variable//' will be treated as a literal string, which does not contain specific_string
sed can modify text from files or STDIN, but not text given via parameters. With sed 's/...//' $input_string the /path/to/some/specific_string/.../file is opened and its content is read, instead of the path itself.
s/string// deletes only string, not the words afterwards.
Also remember to double quote your variables. cmd $variable is dangerous if the variable contains spaces. cmd "$variable" is safe.
Sed Solution
output="$(sed "s/$variable.*/$variable/" <<< "$input_string")"
GNU Grep Solution
output="$(grep -Po "^.*?$variable" <<< "$input_string")"
Pure Bash Solution
output="${input_string%%$variable*}$variable"
If you want to remove everything after "specific_string" it will remove the "/" also as it does with the following example:
output=$(echo $input_string|sed "s/${variable}.*$/${variable}/")
try with simple sed:
variable="specific_string"
input_string="/path/to/some/specific_string/specific_string.something/specific_string.something-else"
output=$(echo "$input_string" | sed "s/\(.*$variable\/\).*/\1/")
Output of variable output will be as follows.
echo $output
/path/to/some/specific_string/

How to use bash variables in sed command?

I want to do (in bash script):
NEWBASE=`echo $NAME | sed "s/${DIR}//g" | sed 's/.\///g'`
I read in the net, that I have to replace single quote with double quote.
This is unfortunately not working. Why? Thanks
sed is overkill for this. Use parameter expansion:
NEWBASE=${NAME//$DIR//}
NEWBASE=${NEWBASE//.\//}
It is important to understand that bash and sed are two completely independent things. When you give bash a command, it first processes it according to its rules, in order to come up with a utility name and a set of arguments for that utility (in this case sed), and then calls the utility with the arguments.
Probably $DIR contains a slash character. Perhaps it looks something like /usr/home/codyline/src.
So when bash substitutes that into the argument to the sed command:
"s/${DIR}//g"
the result is
s//usr/home/codyline/src//g
which is what is then passed to sed. But sed can't understand that commabnd: it has (many) too many / characters.
If you really want to use sed for this purpose, you need to use a delimiter other than /, and it needs to be a character you are confident will never appear in $DIR. Fortunately, the sed s command allows you to use any character as a delimiter: whatever character follows the s is used as the delimiter. But there always must be exactly three of them in the command.
For example, you might believe that no directory path contains a colon (:), in which case you could use:
sed "s:${DIR}::g"
Of course, someday that will fail precisely because you have a directory with a colon in its name. So you could make things more general by using bash's substitute-and-replace feature to backslash-escape all the colons:
sed "s:${DIR//:/\:}::g"
But you could have used this bash feature in order to avoid the use of sed altogether:
NEWBASE=${NAME//$DIR}
Unfortunately, you can't nest bash substitute-and-replaces, so you need to do them sequentially:
NEWBASE=${NEWBASE//.\/}
Note: I used ${var//...}, which is the equivalent of specifying the g flag in a sed s command, but I really don't know if it is appropriate. Do you really expect multiple instances of $DIR in a single path? If there are multiple instances, do you really want to remove all of them? You'll have to decide.

Resources