Remove string before and after characters in bash - bash

I have a string like : 2021_03_19/ 19-Mar-2021 11:55 -
stored in a variable a
I tried to extract from it the sequence: 2021_03_19, the second one after /"> sequence with the following script:
a=${a##'/">'}
a=${a%%'/</a'}
But the final result is the same string as the input.

The pattern in the parameter expansion needs to match the entire string you want to remove. You are trying to trim the literal prefix /"> but of course the string does not begin with this string, so the parameter expansion does nothing.
Try
a=${a##*'/">'}
a=${a%%'/</a'*}
The single quotes are kind of unusual; I would perhaps instead backslash-escape each metacharacter which should be matched literally.
a=${a##*/\"\>}
a=${a%%/\</a*}

You have to match the before and after pattern too.
a=${a##*'/">'}
a=${a%%'/</a'*}

You could use:
a='2021_03_19/ 19-Mar-2021 11:55 -'
b=${a#*>}
c=${b%%/<*}
Based on Extract substring in Bash
In your example you want to select based on 3 characters but have ##, not ###. I did try that but doesn't seem to work either. So, therefore an alternative solution.

Related

BASH - Replace substring "$$" with substring "$$$"

Essentially what I am trying to do is take a string with a bunch of text and if it has a substring of "$$" to replace it with a substring of "$$$"
ex:
string="abcde\$\$fghi"
# Modify string
echo $string
# ^ should give "abcde$$$fghi"
I have been at this for like 2 hours now and it seems like a very simple thing, so if anyone could provide some help then I would greatly appreciate it. Thanks!
EDIT: Changed original string in the question from "abcde$$fghi" to "abcde\$\$fghi"
$$ is a special variable in the shell, it contains the ID of the current process. The variables are expanded in double quotes, therefore string does not contain $$ but a number (the PID of shell) instead.
Enclose the string in apostrophes (single quotes) to get $$ inside it.
The replacement you need can be done in multiple ways. The simplest way (probably) and also the fastest way (for sure) is to use / in the parameter expansion of $string:
echo "${string/'$$'/'$$$'}"
To make it work you have to use the same trick as before: wrap $$ and $$$ in single quotes to prevent the shell replace them with something else. The quotes around the entire expression are needed to preserve the space characters contained by $string, otherwise the line is split to words by whitspaces and and echo outputs these words separated by one space character.
Check it online.
If you quote the string with single quote marks (i.e. string='abcde$$fghi') you can do the replacement with echo "${string/'$$'/'$$$'}"
Edit: this is basically what #axiac said in their comment

Braces in shell parameter expansion don't work right

I have a program parsing two files and comparing them looking for conflicts between the two and allowing the user to decide what action to take. As a result, I need to be able to parse the lines below. If a string contains { or } when using pattern replacement parameter expansion it will cause an error.
I was looking for a potential work around for the following lines
F=TSM_CLASS="Test text {class}"
newstring=${F//{class}/\\{class\\}}
Results:
echo $newstring
TSM_CLASS="Test text }/\{class\}}"
${F//{class} is a complete parameter expansion which replaces every instance of {class in F's value with empty string. To embed braces in the pattern and/or the replacement string, you need to quote them.
$ F=TSM_CLASS="Test text {class}"
$
$ echo "${F//{class\}/\\{class\\\}}"
TSM_CLASS=Test text \{class\}

Simple bash function to find/replace string variable (no files)

I simply want a function (or just a 1-liner) to find/replace a string inside a variable, and not worry if the variables contain crazy characters.
Pseudo-code:
findReplace () {
#what goes here?
}
myLongVar="some long \crazy/ text my_placeholder bla"
replace="my_placeholder"
replaceWith="I like hamburgers/fries"
myFinalVar=$(findReplace $myLongVar $replace $replaceWith)
All similar questions seem complicated and use files
You can define the function like this:
findReplace1() {
printf "%s" "${1/"$2"/$3}"
}
And then run it like this:
myFinalVar=$(findReplace "$myLongVar" "$replace" "$replaceWith")
Note the double-quotes -- they're very important, because without them bash will split the variables' values into separate words (e.g. "some long \crazy/ text..." -> "some" "long" "\crazy/" "text...") and also try to expand anything that looks like a wildcard into a list of matching filenames. It's ok to leave them off on the right side of an assignment (myFinalVar=...), but that's one of the few places where it's ok. Also, note that within the function I put double-quotes around $2 -- in that case again it's to keep it from being treated as a wildcard pattern, but here it'd a string-match wildcard rather than filenames. Oh, and I used printf "%s" instead of echo because some versions of echo do weird things with strings that contain backslashes and/or start with "-".
And, of course, you can just skip the function and do the replacement directly:
myFinalVar=${myLongVar/"$replace"/$replaceWith}
Try:
myFinalVar=${myLongVar/$replace/$replaceWith}
If your want to replace all occurrences of $replace, not just the first, use:
myFinalVar=${myLongVar//$replace/$replaceWith}
Documentation
From man bash:
${parameter/pattern/string}
Pattern substitution. The pattern is expanded to produce a pattern
just as in pathname expansion. Parameter is expanded and the longest
match of pattern against its value is replaced with
string. If pattern begins with /, all matches of pattern are
replaced with string. Normally only the first match is replaced. If
pattern begins with #, it must match at the beginning of
the expanded value of parameter. If pattern begins with %, it must
match at the end of the expanded value of parameter. If string is
null, matches of pattern are deleted and the / following pattern may
be omitted. If the nocasematch shell option is enabled, the match is
performed without regard to the case of alphabetic
characters. If parameter is # or *, the substitution operation is
applied to each positional parameter in turn, and the
expansion is the resultant list. If parameter is an array variable
subscripted with # or *, the substitution operation is applied to each
member of the array in turn, and the expansion is the
resultant list.

Sed or String Replace command in Unix to change last First Character after Sequence to UpperCase

I basically have these xml files where I need to change the first alphabet after
Eg.
Result:
I tried: sed 's/<structure name=\"/\U\/g'
However, this changes the entire word to uppercase. Can someone help me out?
\U is for converting all characters. You will need to use \u to convert the first occurrence.
Also, you will need to group them to ensure correct letter is converted:
sed 's/\(<structure name=\"\)\(.\)/\1\u\2/' xml-file
sed 's/<structure name=\"\(.\)/<structure name=\"\U\1/'
sed will only convert strings being substituted to uppercase. We can use a capturing group to only convert the first character after the sequence to uppercase.
Otherwise, you can also use \E, which is similar to \U, except it stops converting characters instead of starting it.

ruby .split('\n') not splitting on new line

Why does this string not split on each "\n"? (RUBY)
"ADVERTISING [7310]\n\t\tIRS NUMBER:\t\t\t\t061340408\n\t\tSTATE OF INCORPORATION:\t\t\tDE\n\t\tFISCAL YEAR END:\t\t\t0331\n\n\tFILING VALUES:\n\t\tFORM TYPE:\t\t10-Q\n\t\tSEC ACT:\t\t1934 Act\n\t".split('\n')
>> ["ADVERTISING [7310]\n\t\tIRS NUMBER:\t\t\t\t061340408\n\t\tSTATE OF INCORPORATION:\t\t\tDE\n\t\tFISCAL YEAR END:\t\t\t0331\n\n\tFILING VALUES:\n\t\tFORM TYPE:\t\t10-Q\n\t\tSEC ACT:\t\t1934 Act\n\t"]
You need .split("\n"). String interpolation is needed to properly interpret the new line, and double quotes are one way to do that.
In Ruby single quotes around a string means that escape characters are not interpreted. Unlike in C, where single quotes denote a single character. In this case '\n' is actually equivalent to "\\n".
So if you want to split on \n you need to change your code to use double quotes.
.split("\n")
Ruby has the methods String#each_line and String#lines
returns an enum:
http://www.ruby-doc.org/core-1.9.3/String.html#method-i-each_line
returns an array:
http://www.ruby-doc.org/core-2.1.2/String.html#method-i-lines
I didn't test it against your scenario but I bet it will work better than manually choosing the newline chars.
Or a regular expression
.split(/\n/)
You can't use single quotes for this:
"ADVERTISING [7310]\n\t\tIRS NUMBER:\t\t\t\t061340408\n\t\tSTATE OF INCORPORATION:\t\t\tDE\n\t\tFISCAL YEAR END:\t\t\t0331\n\n\tFILING VALUES:\n\t\tFORM TYPE:\t\t10-Q\n\t\tSEC ACT:\t\t1934 Act\n\t".split("\n")

Resources