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.
Related
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.
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.)
In sed, you can end a command with the flag "/i" (for example, see this other question). This seems to say "more sed commands coming," or something like that, so you can split sed commands in a script. Or maybe not— I can't find any documentation on this flag.
It's a modifier to the regular expression which makes it case-insensitive. For instance, s/\ XVID//i would replace " xViD" (or any other capitalization of those four letters) with nothing.
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# )
I'm having difficulty getting this bash script to perform the formatting of an input.
It's pretty straight-forward, but when it executes the line that starts with 'newstring=', it doesn't perform the sed operation, it only prints my input (up until the first white-space) then prints my sed command directly after. What am I doing wrong?
#! /bin/bash
##format paths/strings with spaces to escape the spaces with a forward-slash'\'
##then use 'open' to open finder at current-set directory (based on path)
oldstring="$1"
newstring="$oldstring | sed 's/ /\\ /g')"
cd $newstring
open .
You should simply do:
cd "$1"
open .
This avoids running sub-processes and deals with various problems that the sed script doesn't (such as names containing $ symbols, or other shell metacharacters). Generally, if a variable (or positional parameter such as $1) is a file name that could contain spaces, use it surrounded by double quotes every time.
Try putting the command in backquotes like
newstring=`echo "$oldstring" | sed 's/ /\\ /g')`
#Jonathan Leffler's is the correct solution, since adding escapes doesn't actually do what you want but double-quoting does. However, I'll take this opportunity to point out that there's a better way to add escapes using bash's built-in substitution capability instead of sed:
newstring="${oldstring/ /\\ }"
So there you have it, a better way to implement the wrong solution. Personally, I voted for Jonathan's.