Friday, May 3, 2024
6
rated 0 times [  6] [ 0]  / answers: 1 / hits: 1916  / 1 Year ago, tue, may 2, 2023, 11:46:03

I have a string variable in a bash script file as follows:


string="

test1

test2

"

and I want to check whether a file test.txt containts this specific string (including the linebreaks. i.e. it should fail if it only contains the following:


this is a test:
test1

test2
and another one

because the linebreaks above test1 and below test2 aren't present.


(The reason I want to check this is because I want to check whether a certain piece of code is in a source file, and if not, add it.)




The following doesn't work:


string="

test1

test2

"
if ! grep -q string "test.txt"; then
echo "$string" >> test.txt
fi

This correctly adds the string to the file, but it does it even if the string has already been added. Also, it performs correctly when I change the string to have no linebreaks.




EDIT:


The answers by @terdon and @steeldriver below work for the string example I wrote above, but they for some reason break for this more realistic example:


string="                                                                

if [ -f ~/.script ]; then
. ~/.script
fi

"

More From » command-line

 Answers
5

The problem is that grep will run on each line, not the entire file. As long as the file is small enough to fit into memory (which should be the case in the vast majority of situations these days), you can use grep's -z flag to slurp the entire file:



-z, --null-data
Treat input and output data as sequences of
lines, each terminated by a zero byte (the ASCII NUL
character) instead of a newline. Like the -Z or --null option, this option can be used with commands
like sort -z to process arbitrary file names.



The next issue, is that if you pass grep something with newlines, it will treat it as a list of patterns to grep for:


$ string="1
> 2"

$ seq 10 | grep "$string"
1
2
10
"

Which means that I am afraid you will have to express the pattern as a proper regular expression:




test1

test2



However, this also means you need the -P flag to enable perl-compatible regular expressions so the
will work.


I created these two files to demonstrate:


$ cat file1
this is a test:
test1

test2
and another one

$ cat file2
this is a test:

test1

test2

and another one

Using those two files and the information above, you can do:


$ grep -Pz '

test1

test2

' file1
$

$ grep -Pz '

test1

test2

' file2
this is a test:

test1

test2

and another one

Putting all this together gives us:


string='

test1

test2

'
if ! grep -Pzq "$string" test.txt; then
printf "$string" >> test.txt
fi

Or, as suggested by @steeldriver in a comment, you can use a variable and convert the newlines to
on the fly:


$ string="

test1

test2

"
$ if ! grep -Pzq "${string//$'
'/n}" test.txt; then
printf "$string" >> test.txt
fi



If your string contains special characters which have meanings in regular expressions, as you now show in your updated question, then that's a whole different situation. For the example you show, you would need something considerably more complicated. Like this:


searchString='

if [ -f ~/.script ]; thens*
s*.s+~/.scripts*
fi

'
printString='
if [ -f ~/.script ]; then
. ~/.script
fi

'
if ! grep -Pzq "$searchString" test.txt; then
printf "%s" "$printString" >> test.txt
fi


[#1131] Wednesday, May 3, 2023, 1 Year  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
kilusy

Total Points: 171
Total Questions: 110
Total Answers: 128

Location: Cayman Islands
Member since Sat, Dec 5, 2020
3 Years ago
kilusy questions
Sat, Jan 15, 22, 04:45, 2 Years ago
Tue, Aug 10, 21, 16:38, 3 Years ago
Thu, Jan 27, 22, 03:19, 2 Years ago
;