Shell How to get a new path by replacing a substring in a path string - linux

I have a path like this:
dirname=../2Reconnaissance-annoted/J39/IMG_2208.json
I want to get a new path by replacing ".json" with "_json", so I tried this command:
tr "\.json" "_json" <<<$dirname
The problem is that I get:
__/2Reconnaissance-annoted/J39/IMG_2208_json
Rather than
../2Reconnaissance-annoted/J39/IMG_2208_json
How do you fix it, please?

tr does transliteration, i.e. it replaces a character by a character, not a string by a string. What you need is substitution.
Most shells support substitution directly:
dirname=${dirname/.json/_json}
(${dirname/%.json/_json} would only substitute the substrings at the end of the string).
If your shell doesn't support it, you can use sed:
echo "$dirname" | sed -e 's/\.json$/_json/'

Related

How to grep for this string that contains an equal sign?

Below is the string I am trying to grep for this in the bash shell:
'#Hostname=sometext.company.com, sometext.company.com' filename
I want to only find the string if it matches that exact pattern. I already tried the command below and a few others.
grep -Fx "#Hostname=sometext.company.com, sometext.company.com" filename
Did you specify the -xoption on purpose?
grep -F '#Hostname=sometext.company.com, sometext.company.com' filename
most likely is what you want. Also, it's better to put single quotes instead of double quotes, just in case your search pattern happens to contain special shell characters.

difficult string to replace in script using SED

I know, many people have had questions on how to use sed to replace a string, but I have a difficult one here.
I have a file I need to replace a string of text that prompts the user to enter content. I want to automate this so the user does not interact. By replacing this string with a static file path. but the text is a bash script and has ' and " within the string I want to replace. It does not work. Either because I have syntax errors in my formatting, or it simply is not possible to do this action with sed. Please advice!
Here is what I am attempting to do:
I want to replace this long string
read -e -p 'Enter path for Boot Partition : ' BOOTUSERFILEPATH
with a string that looks like this:
BOOTUSERFILEPATH=../board-support/prebuilt-images
My attempt:
sed -i "/read -e -p 'Enter path for Boot Partition : ' BOOTUSERFILEPATH/BOOTUSERFILEPATH="../board-support/prebuilt-images"" file_to_search.sh
Update: I fixed the syntax error, but file still is not updated with the new path information... :(
found the problem. the search was not finding the strings because of an extra space in my search command. It works now!
There are forward slashes in your string so one needs to use a different delmiter. Here I use '|' as the delimiter.
sed "s|read -e -p \'Enter path for Boot Partition : \' BOOTUSERFILEPATH|BOOTUSERFILEPATH=../board-support/prebuilt-images|g" oldfile > newfile
You may note that the -i option to sed which allows files to be edited in place is not a POSIX supported option.
However if you wish to use it:
sed -i "s|read -e -p \'Enter path for Boot Partition : \' BOOTUSERFILEPATH|BOOTUSERFILEPATH=../board-support/prebuilt-images|g" oldfile
You may find it easier to use a pattern with sed which matches part of this string and then replaces its entirety:
sed 's|read -e -p .* BOOTUSERFILEPATH|BOOTUSERFILEPATH=../board-support/prebuilt-images|g' filename > newfilename
From the POSIX specification page for sed:
s/BRE/replacement/flags
Substitute the replacement string for instances of the BRE in the pattern space. Any character other than <backslash> or <newline> can be used instead of a slash to delimit the BRE and the replacement.
You need to use an actual substitute command, and you need to avoid the slashes in the replacement text from confusing sed. Personally, I'd probably use:
sed -i.bak "s%^read .* BOOTUSERFILEPATH$%BOOTUSERFILEPATH=../board-support/prebuilt-images%" file_to_search.sh
or even more likely:
BOOTUSERFILEPATH="../board-support/prebuild-images"
sed -i.bak "s%^read .* BOOTUSERFILEPATH$%BOOTUSERFILEPATH=$BOOTUSERFILEPATH%" file_to_search.sh
The s%%% uses % instead of / to delimit the parts of the command. I cheated on the match pattern, working on the assumption that you don't have many similar lines in the file.

Replace shortest string match in bash

In bash, there are several useful string manipulation patterns, such as removing shortest/longest substring from beginning/end of the string:
${var#substring}
${var##substring}
${var%substring}
${var%%substring}
Then there is also the replacement pattern, that replaces a substring from any part of the string:
${var/substring/replacement}
The problem with this is that it is greedy and always replaces the longest match. For example if I have a directory name like /a/b/foo-bar/x/y/z and I want to replace any subdirectory name starting with foo- to baz, then it won't work as I expect. I expect the result to be /a/b/baz/x/y/z. I tried the following command:
${PWD/\/foo-*\///baz/}
The result in this case is /a/b/baz/z, because the pattern matches the longest substring starting with /foo- and ending with /. Is there any way to get the correct result without calling sed or any other external string manipulation program?
Of course, you can always use extended globs:
shopt -s extglob
var=/a/b/foo-bar/x/y/z/foo-bar2/1/2/3
echo "${var//\/foo-*([^\/])\///baz/}"
will happily output
/a/b/baz/x/y/z/baz/1/2/3
In pure BASH you can do this (using BASH regex capabilities):
s='/a/b/foo-bar/x/y/z'
p="$s"
[[ "$s" =~ ^(.*/)'foo-'[^/]*(.*)$ ]] && p="${BASH_REMATCH[1]}baz${BASH_REMATCH[2]}"
echo "$p"
/a/b/baz/x/y/z
Here's a way to do it in pure Bash that replaces all subdirectories in the path that match the pattern. It splits the path into an array, does the replacement on each path component into a new array, and then uses printf to replace the path separators.
name='/a/b/foo-bar/x/foo-y/z';
IFS=$'/';
aname=($name);
bname=();
for i in "${aname[#]}";
do bname+=("${i/foo-*/baz}");done;
printf -v newname "%s/" "${bname[#]}";
printf "%s\n" "$newname"
output
/a/b/baz/x/baz/z/
(Sorry about all the ;s, I just did a quick copy & paste from the shell)
you cannot use regex in bash's built-in string substitution. If you have to stick to the built-in string manipulation, you have to extract the substring foo-bar first then use it in your ${PWD/$match/baz}.
You can do it very easily however, if you could use regex. There are a lot of handy string handlers under linux/unix, could do that very easily. sed for example:
kent$ sed 's#/foo-[^/]*#/baz#' <<< '/a/b/foo-bar/x/y/z'
/a/b/baz/x/y/z

How to use variables in linux regex pattern?

I need to execute a sed command with pattern /^03.06.2014/ in a .sh script & command line. The date is a variable not a constant. How could i implement this? When I use a variable inside a regex pattern, the command breaks. Do I need to escape something here? Any help is appreciated. Thanks!
date=$(date +%m.%d.%Y)
sed -n '/^$date/,$p' filename
Use double quotes for variable expansion in sed
sed -n "/^$date/,\$p" filename
You need to use double quotes to allow for shell expansion. You'll need to escape the $ meaning EOF.
sed -n "/^$date/,\$p" filename

Split a string based on backslash delimiter

I'm new to bash scripting. I have a string which is like so: \\abc\def\ghi
I want to parse the string using a delimiter and need a one line command for converting it to /abc/def/ghi (convert Windows path to unix path).
Try doing this :
$ x='\abc\def\ghi'
$ echo ${x//\\//}
/abc/def/ghi
See parameter expansion
NOTE
parameter expansions are bash built-ins, so it's quicker than external commands
string=$( echo "$string" | tr '\' '/' )
or with sed:
kent$ echo -E "\abc\def\ghi"|sed 's:\\:/:g'
/abc/def/ghi

Resources