2

I have a file with multiple lines in it. I am trying to get a string that appears after a specific pattern...

Here is the command i am trying to do:

sed -n -e 's/^.*DB_PASS=//p' <<< $(cat /root/dadosDB)

But instead of giving me only the line i want, its giving me everything after the pattern I specified...

What I expect:

Return only the output of the line that contains DB_PASS and ignore other lines.

What the command is doing:

Printing everything of the entire file after DB_PASS and ignoring everything that appears before that pattern.

Any help is apprreciate it!

Here is what I have inside dadosDB:

DB_USER=myusername
DB_PASS=mypassword
DB_NAME=mydatabase

I want to get only what is after DB_PASS= and stop at that line, ignoring the following ones.

Actual output of the sed:

$ sed -n 's/^.*DB_PASS=//p' <<< $(cat /root/dadosDB)
mypassword DB_NAME=mydatabase

What I need:

mypassword
AdminBee
  • 22,803
  • 1
    Could you share with us an example of the file? [edit] the question adding it. – schrodingerscatcuriosity Sep 28 '21 at 14:28
  • 1
    Done... I just edited and added more information. – Raul Chiarella Sep 28 '21 at 14:34
  • 1
    How important is your requirement to stop at that line, ignoring the following ones? None of the current answers do that, they all continue to read the rest of the file after finding the matching line so - do you require that because your file is particularly huge or because there might be a second DB_PASS=mypassword line that you don't want matched or something else? Or do you actually not need that at all? – Ed Morton Sep 28 '21 at 14:47

3 Answers3

2

The reason why you are getting this result is because you don't apply the sed command to the file directly, but to the result of a command substitution.

This means that the text processing is not actually applied to

DB_USER=myusername
DB_PASS=mypassword
DB_NAME=mydatabase

but to the result of the cat command applied to the file content, after an unquoted command substitution that squeezes the lines.

If you try

echo $(cat /root/dadosDB)

you will notice that the output is

DB_USER=myusername DB_PASS=mypassword DB_NAME=mydatabase

all on a single line, rather than on separate lines. If you place the command substitution in double-quotes, as in

echo "$(cat /root/datosDB)"

the newlines will be preserved.

The key points are that

  1. you need neither the cat nor the command substitution, and
  2. if you use the command substitution without placing it in double-quotes, you will lose the newlines (see this Q&A e.g.).(1)

TL;DR:

Use

sed -n -e 's/^.*DB_PASS=//p' /root/dadosDB

or (rather)

sed -n -e 's/^DB_PASS=//p' /root/dadosDB

to exclude lines with keywords that start differently, but end in DB_PASS.

Please note: You write "and stop at that line, ignoring the following ones." I took this as meaning that you want to print the word after DB_PASS, but not the following lines (that technically also come after DB_PASS. If you mean that there could be more lines starting with DB_PASS and you want to ensure matching only the first, you will need a slight adjustment:

sed -n -e '0,/DB_PASS/s/^DB_PASS=//p' /root/dadosDB

(1) Note that the issue in your particular case is how your shell (I assume Bash) handles "Here-strings" with unquoted substitutions, so (as noted by @steeldriver) a better demonstration is

cat <<< "$(cat /root/dadosDB)"

vs.

cat <<< $(cat /root/dadosDB)

The behavior has changed with Bash v4.4: Before, the output of the two commands was different in the same way as the echo examples mentioned above. In later versions of Bash, the unquoted command substitution would no longer lead to word-splitting and consequent squeezing of multi-line output.


If you are interested to learn more, you may want to look at

Also, I would recommend checking your scripts with shellcheck, also available as standalone tool on many Linux distributions, to avoid syntax (and other) errors.

AdminBee
  • 22,803
2

You can also use awk, which seems (to me) a more suited option than sed for the task:

$ awk -F'=' '$1 == "DB_PASS" { print $2 }' /root/dadosDB
mypassword

Another option is a combination of grep and cut:

$ grep "^DB_PASS=" /root/dadosDB | cut -d= -f2
mypassword

Note both commands treat the input as columns separated by =.

jubilatious1
  • 3,195
  • 8
  • 17
  • 1
    @RaulChiarella the best approach in general is to try to use the more suited tool for the job (not that I'm telling my selection is the correct one necessarelly). Knowing a little of each parsing text tool cut, grep, awk, etc, can save you time and get better results. – schrodingerscatcuriosity Sep 28 '21 at 14:55
-1

Try this:

sed -n "s/.*DB_PASS=\(.*\)/\1/p" <<< $(cat /root/dadosDB)

If it's just one line ->

echo "DB_USER=myusername DB_PASS=mypassword DB_NAME=mydatabase" | sed -n "s/.*DB_PASS=\(.*\)DB.*/\1/p"
K-attila-
  • 642
  • 1
    Unfortunately, this would give the same result as the OP's attempt because the underlying problem - applying the sed call to the unquoted result of a command substitution rather then the file content - is not solved. – AdminBee Sep 28 '21 at 14:48
  • Didnt work. Thanks tho... – Raul Chiarella Sep 28 '21 at 14:52
  • Wow. echo "DB_USER=myusername DB_PASS=mypassword DB_NAME=mydatabase" | sed -n "s/.DB_PASS=(.)DB.*/\1/p" Just for fun..... – K-attila- Sep 28 '21 at 15:00
  • I copy-and-pasted your example command, and the result was the same as what the OP posted as "unwanted output" (i.e. mypassword DB_NAME=mydatabase) – AdminBee Sep 28 '21 at 15:02
  • The comment field "eat" the backslash.... – K-attila- Sep 28 '21 at 15:03
  • 1
    Regarding sed -n "s/.*DB_PASS=\(.*\)/\1/p" - don't use double quotes around strings (including scripts) unless you need to, use single quotes instead. See https://mywiki.wooledge.org/Quotes. Regarding $(cat /root/dadosDB) that will concatenate the whole input file onto 1 line, you do need double quotes around that, "$(cat /root/dadosDB)" but it'd be more concise as just sed '...' < <(cat /root/dadosDB) or sed '...' < '/root/dadosDB' or just a plain old sed '...' '/root/dadosDB' – Ed Morton Sep 28 '21 at 16:49
  • 1
    The echo | sed command isn't useful as it's not what the OP needs to do (operate on a file) and it's very fragile, e.g. try echo 'DB_USER=myusername DB_PASS=mypassword DB_NAME=mydatabase DB_FOO=bar' | sed -n 's/.*DB_PASS=(.*)DB.*/\1/p' – Ed Morton Sep 28 '21 at 16:50