Bash grep pattern matching on a substring [closed] - bash

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm struggling a little bit with grep pattern matching. I thought ${d%?} would match on all but the last character, but it seems to be matching more aggressively than that.
dbs=$(${db_home}/bin/srvctl config | sort)
counter=1
for d in ${dbs[#]};do
echo -e "dbs[${counter}] = ${d}"
inst2[${d}]=$(sudo ${grid_home}/bin/crsctl stat res -w "((TYPE = ora.database.type) AND (LAST_SERVER = $(hostname -s)))" -f | grep ^USR_ORA_INST_NAME= | grep ${d%?})
echo -e "inst2[${d}] = ${inst2[${d}]}"
I'd expect my output to be something like
dbs[1] = ope3u005
inst2[ope3u005] = USR_ORA_INST_NAME=ope3u0051
dbs[2] = ope3u006
inst2[ope3u006] = USR_ORA_INST_NAME=ope3u0061
But instead I'm getting
dbs[1] = ope3u005
inst2[ope3u005] = USR_ORA_INST_NAME=ope3u0051
USR_ORA_INST_NAME=ope3u0061
dbs[2] = ope3u006
inst2[ope3u006] = USR_ORA_INST_NAME=ope3u0051
USR_ORA_INST_NAME=ope3u0061
It's pretty clearly stripping off more than the last character for matching.
This isn't a use case for where we need to strip off the last character, but I'm trying to find a solution that works for this case as well as the cases where we do need to.

If you strip the final character off "ope3u005" then obviously it's going to match both "ope30051" and "ope3u0061"

Related

Best way to alter a file in a bash script [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
i have a file that have variables and values
objective: open the file and replace all id by input id
[FILE]
var1 = 2
id = 3
var3 = 5
id = 12
var4 = 5
and i can't replace the id values to new ones.
here's my code, any help or something will help. thanks
#!/bin/bash
filename=$1
uuid=$2
input="./$filename"
# awk -v find="id " -v field="5" -v newval="abcd" 'BEGIN {FS=OFS="="} {if ($1 == find) $field=newval; print $1}' $input
while IFS= read -r line
do
awk -v find="id " -v field="5" -v newval="abcd" 'BEGIN {FS=OFS="="} {if ($1 == find) $field=newval;}' $input
echo $line
done < "$input"
expected output
execute
./myscript.sh file.cnf 77
expected output:
[FILE]
var1 = 2
id = 77
var3 = 5
id = 77
var4 = 5
I think sed is the right tool for this. You can even use its -i switch and update the file in-place.
$ cat file.txt
var1 = 2
id = 3
var3 = 5
id = 12
var4 = 5
$ NEW_ID=1234
$ sed -E "s/(id\s*=\s*)(.+)/\1${NEW_ID}/g" file.txt
var1 = 2
id = 1234
var3 = 5
id = 1234
var4 = 5
The string inside the quotes is a sed script for substituting some text with different text, and its general form is s/regexp/replacement/flags where "regexp" stands for "regular expression".
In the above example, the script looks for the string "id = ..." with any number of spaces or tabs around the "=" character. I divided the regexp into 2 groups (using parentheses) because we only want to replace the part to the right of the "=" character, and I don't think sed allows partial substitutions, so as a workaround I used \1 in the "replacement", which inserts the contents of the 1st group. The ${NEW_ID} actually gets evaluated by the shell so the value of the variable ("1234") is already part of the string by the time sed processes it. The g at the end stands for "global" and is probably redundant in this case. It makes sure that all occurrences of the regex on every line will get replaced; otherwise sed would only replace the first occurrence on each line.
Not sure. Bash scripts are extremely sensitive. I'm guessing your touch is what is causing this issue for a couple of reasons.
First whenever you touch a file name is should not consist of an operand or prefix unliss it is part of the shell script and $filename is shell or inline block quote. Touch is usually used for binaries or high priority data objects.
Second I'd try changing input and adjusted to $done and instead of echoing the $line echo the entire script using esac or end if instead of a do while loop.

Bash-script won't work, initializing a variable (string) with output of sed [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have some trouble with this script.
#!/bin/bash
i=1
for i in $(cat rows.txt);
do
j = "$(sed -ne "$[i-1]p" LOB_final.html)"
echo $j
sed -ne "$[i-1],$[i+4]p" LOB_final.html >> ./cards/$j.txt
done;
I have an other file that contains the right row-numbers (not exactly, [row-1] is the relevant row). This row contains a string with spaces included and should be the name of the file.
Script works so far as expected, but initializing j don't work.
Does anyone have a tip?
Thank you.
EDIT: The goal was, to write any six rows (1 before and 4 after ans the given row) in a file. The file should be named with the 1 before row of the given row (a string with white spaces included).
Questions is cleared, thanks to all.
check this, have fixed quite a few issues with your script
#!/bin/bash
i=1
for i in $(cat rows.txt);
do
j="$(sed -ne "$((i-1))p" LOB_final.html)"
echo "$j"
sed -ne "$((i-1)),$((i+4))p" LOB_final.html >> ./cards/"$j".txt
done;
Removed space which was there in assigning j
$[var] replaced with $((var))
Expanded variables in double quotes
You seem to want to get the filename from line i-1 and then to store that line together with the next five lines in a file with that name.
Using awk:
awk 'NR == FNR { rows[$0]; next }
FNR + 1 in rows { name = sprintf("./cards/%s.txt", $0); left = 6 }
left > 0 { print >name; --left }' rows.txt LOB_final.html
This has been tested on some toy data, but since I don't know what your data looks like I can't say for certain that it will work without (minor) modifications.
It has the benefit that it will not parse the whole of LOB_final.html twice for each row number read from rows.txt, which your original code does. In fact, it only ever reads each file once.

Replace periods with substitution in bash script using perl except questionmark or exclamation mark

Originally I figured out how to remove the periods for all the files and then add them back:
Remove periods at end of titles
perl -pi -e 's/title = \{(.*)\.\},/title = \{$1\},/g' $1
# Add periods back so all files are the same (comment out if no periods wanted)
perl -pi -e 's/title = \{(.*)\},/title = \{$1\.\},/g' $1
Ideally what I want to do is check if every title has a period, exclamation mark, or question mark and if it doesn't then add a period. I assume there is a simple way to do this substitution but I don't know the syntax well.
So for example for input:
title = This has a period.
title = This has nothing
title = This has a exclamation!
title = This has a question?
The output will be:
title = This has a period.
title = This has nothing.
title = This has a exclamation!
title = This has a question?
So it only modifies lines to had a period if it ended without any markings.
KISS, Use negated character class.
perl -pi -e 's/title = \{(.*[^.?!])\},/title = \{$1\.\},/g' $1
DEMO
or
Use negative lookbehind.
perl -pi -e 's/title = \{(.*)(?<![.?!])\},/title = \{$1\.\},/g' $1
DEMO
You can use this sed:
sed '/^title = .*[.!?]$/!s/$/./' file
(OR)
sed '/^title = .*[^.!?]$/s/$/./' file
Test:
$ sed '/^title = .*[.!?]$/!s/$/./' file
title = This has a period.
title = This has nothing.
title = This has a exclamation!
title = This has a question?

Grep string if it has multiple match [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
It was hard to formulate a question, better i will show example.
Txt file has these lines
city:state:address
city:state
city:
I need to extract strings where
a) only one occurrences of :
b) only one occurrences of : and has value after :
c) two occurrences of :
and put these strings to deferent files, so one file will contain all strings with
city:state:address second with city:state third one city:
Note: File has many such strings. Not obligatory to create three files in one command. It will be enough one command where i may define how many : string should contain.
Use these invocations of grep and pipe the output into different files:
grep -E "^[^:]+:\s*$" file.txt
grep -E "^[^:]+:[^:]+$" file.txt
grep -E "^[^:]+:[^:]+:.*$" file.txt
It looks for something that is not : with the regex [^:]+. It uses ^ and $ at the begin and end to match the whole input line.
This is a job for awk, not grep. All you need is:
awk -F':' '
NF==3 { print > "file_c"; next }
{ print > ($2=="" ? "file_a" : "file_b") }
' file
and that'll create all the files you want in one pass of your input file.
If you have more fields and more rules just write them all down so they're mutually exclusive, e.g. you could implement the above as:
NF==3 { print > "file_c" }
NF==2 && $2=="" { print > "file_a" }
NF==2 && $2!="" { print > "file_b" }

ruby and sed -n matched group [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Doing git config -l | sed -n 's/^user.name=\(.*\)$/{\1}/p' in the shell will yield the current "user.name" set in the git config. But if I do this same command in backticks `` or with %x(<shel code>) in ruby, I get nothing returned.
I've found another way around without using sed in this case, but I'm wondering why I can get the output of sed without the -n flag, which would be whatever is piped to it, but I can never get the matched group (whether it be by itself or part of the stream that sed without the -n outputs).
You could do most of that in ruby:
conf = %x{git config -l}
if m = conf.match(/^user.name=(.*)/)
username = m[1]
end
To directly answer your question, the text in %x{} is subject to the same substitutions as double quoted strings, so you need to escape the backslashes:
irb(main):023:0> u = %x{git config -l | sed -n 's/^user.name=\(.*\)$/{\1}/p'}
=> ""
irb(main):024:0> u = %x{git config -l | sed -n 's/^user.name=\\(.*\\)$/{\\1}/p'}
=> "{Glenn Jackman}\n"
Or you could store the command in a single quoted string:
irb(main):020:0> cmd = %q{git config -l | sed -n 's/^user.name=\(.*\)$/{\1}/p'}
=> "git config -l | sed -n 's/^user.name=\\(.*\\)$/{\\1}/p'"
irb(main):022:0> u = %x{#{cmd}}
=> "{Glenn Jackman}\n"

Resources