Precedence of heredocs and compound commands in bash - bash

I want my shell script to print out a simple usage instruction and then exit when it is called without arguments. Here's what I tried:
#!/bin/bash
(($#)) || cat <<EOF && exit
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Usage: Donec a diam lectus.
EOF
echo "You have provided at least one argument"
(The special bash variable $# holds the number of arguments, and surrounding it with double parentheses makes it evaluate to false when there are no arguments).
This works when there are no arguments, but exits immediately without printing anything if there are arguments. I thinks it's due to the wrong precedence of the operators. How can I fix this script to do what I want?

use curly braces to group the commands:
(($#)) || { cat <<EOF && exit
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Usage: Donec a diam lectus.
EOF
}
echo "You have provided at least one argument"
Or you could just give up on the compact format, and use if:
if [[ $# == 0 ]]
then cat <<EOF && exit
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Usage: Donec a diam lectus.
EOF
fi
echo "You have provided at least one argument"

Related

Notepad++ Syntax colouring: Delimiter style closes on end-of-line

I'm making a new colouring syntax for Notepad++.
I'd like to detect and mark the "some_method_name" in the following text:
method::some_method_name
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, ...
I wanted to use a "Delimiter style" with "::" as Open param, and End of line as Close param. But I don't know how to write this "end of line".
I tried \n, \\n, \n\r, \\n\\r, \\r\\n, but none are working.
How to approach this syntax colouring ?

Remove blank line after a 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 3 years ago.
Improve this question
Imagine the following example input file:
(1) Lorem ipsum dolor sit amet
vero eos et accusam et justo duo
(2) Lorem ipsum dolor sit amet
vero eos et accusam et justo duo
(3) Lorem ipsum -- dolor sit amet
vero eos et accusam et justo duo
(4) Lorem -- ipsum dolor sit amet
vero eos et accusam et justo duo
I am interested in finding all lines ending with the keyword amet and not containing the keyword -- in a script. If such a line is found the successor line should be removed if it is blank. So only the second (2) example has to be changed:
(1) Lorem ipsum dolor sit amet
vero eos et accusam et justo duo
(2) Lorem ipsum dolor sit amet
vero eos et accusam et justo duo
(3) Lorem ipsum -- dolor sit amet
vero eos et accusam et justo duo
(4) Lorem -- ipsum dolor sit amet
vero eos et accusam et justo duo
This sed command would work:
sed '/--/b;/amet$/{N;s/\n$//;}'
It does the following:
/--/b # If line matches "--", skip all commands
/amet$/ { # If the line ends in "amet"
N # Read next line into pattern space
s/\n$// # Delete the second line if it is blank
}
This would fail for a few edge cases: does a line ending in blamet qualify? Does -- have to be separated by blanks? Could there ever be input like this:
ends in amet
also ends in amet
next line
as the solution presented would not remove the blank line here. For the presented input, though, it would work.
Let's create it bit by bit:
Process only lines that end with amet (using the GNU \b to match a word boundary):
/\bamet$/
If it doesn't contain --
/--/!
Then print the line
n
And if the next line is empty, delete it
/^$/d
That gives this simple program:
#!/bin/sed -f
# Process only lines that end with `amet`:
/\bamet$/{
# If it doesn't contain `--`
/--/!{
# Then print the line
n
# And if the next line is empty, delete it
/^$/d
}
}

Insert two line breaks inbetween merged files using PASTE

I'm using the following command to merge several files: paste -d"\n \n" -s *.md > big-markdown-file.md.
My issue is that there is only one line break between the merged files:
# This is the start of
Lorem ipsum dolor sit amet, te eos solet copiosae deterruisset, mea eu augue postulant temporibus. Sit ex definiebas referrentur. This is the end of file1.
# This is the start of File2.md
Lorem ipsum dolor sit amet, te eos solet copiosae deterruisset, mea eu augue postulant temporibus. Sit ex definiebas referrentur. This is the end of file2.
# This is the start of File3.md
Lorem ipsum dolor sit amet, te eos solet copiosae deterruisset, mea eu augue postulant temporibus. Sit ex definiebas referrentur. This is the end of file3.
This causes issues when the markdown is processed, turning the lorem ipsum paragraphs into headings. Is there a way to introduce 2 line breaks between the individual pastes in the final file so that it outputs something like this:
# This is the start of
Lorem ipsum dolor sit amet, te eos solet copiosae deterruisset, mea eu augue postulant temporibus. Sit ex definiebas referrentur. This is the end of file1.
# This is the start of File2.md
Lorem ipsum dolor sit amet, te eos solet copiosae deterruisset, mea eu augue postulant temporibus. Sit ex definiebas referrentur. This is the end of file2.
# This is the start of File3.md
Lorem ipsum dolor sit amet, te eos solet copiosae deterruisset, mea eu augue postulant temporibus. Sit ex definiebas referrentur. This is the end of file3.
Maybe "cheat" and create a dummy file?
$ touch dummy
$ paste -d"\n" -s *.md dummy > big-markdown-file.md
$ rm dummy # :)
I think it will cause paste to try and consume the next line from the empty file, "fail", and create an empty line instead.
Actually, for a list of file you'll have to create a dummy for each:
$ # create dummy files
$ for f in *.md; do echo $f; touch ${f}_dummy.md; done
$ # create the result files
$ paste -d"\n" -s *.md > big-markdown-file.md
$ # remove dummy files
$ find -name '*dummy.md' -delete

vbScript ignore many blank spaces after split

When I split a string with many spaces, is there a way to skip blank spaces?
Example string below:
Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Morbi cursus quam sapien, sed ultricies diam vestibulum ac.
Morbi luctus nisl eleifend mi tincidunt,
sed vehicula magna lobortis.
When split, the array contains many positions of " " (blank spaces)
[0] Lorem
[1] " "
[2] " "
[3] " "
[4] " "
[5] Ipsum
So, is there a way to skip this blank spaces and get something like this?
[0] Lorem
[1] Ipsum
[3] dolor
Here's my code:
strTmp = split(tmpstr," ")
For each text in strTmp
'Here I validate other things
If InStr(x,textToFind) Then
print "text found"
Else
print "not found"
End If
Next
One of the way is to process the string before splitting it.
Sample Code
varStr = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi cursus quam sapien, sed ultricies diam vestibulum ac. Morbi luctus nisl eleifend mi tincidunt, sed vehicula magna lobortis"
' this is what you are getting right now
arrStr = Split(varStr, " ")
Set objRegEx = CreateObject("VBScript.RegExp")
With objRegEx
.Global = True
.MultiLine = True
.Pattern = "\s+" 'matches any whitespace character
varStr1 = objRegEx.Replace(varStr, "¬")
End With
Set objRegEx = Nothing
' this is what you want
arrStr1 = Split(varStr1, "¬")
I have first stripped all spaces and replaced it with a single ¬ which will act as a delim when I split the string later on.
Can do a loop on the string, and replace double spaces with single spaces
Do Until InStr(text, " ") = 0
text= Replace(text, " ", " ")
Loop
You can try this
If trim(text) <> "" Then
Else
End if
Or
If len(trim(text)) > 0 Then
Else
End if

can I concatenate 2 strings in shell the same way as in C?

I'm writing a script which should provide an option -h for help, when I try to write the help-message, I want to make it look more decent, like this:
print_help()
{
printf "Usage:
./prog -v version
-h help
-x ...."
}
And when I run the script, the help-message should be printed as I wrote it, like this:
Usage:
./prog -v version
-h help
-x ....
In C, I can concatenate 2 strings in two lines like this:
printf("Usage:\n"
"./prog -v version\n"
" -h help\n"
" -x ....\n");
these two lines will be concatenated together and then printed out.
I want to do pretty much the same thing in shell, and I tried printf and echo, seems cannot make it.
Any other advice?
I can think of 2 ways to do this
Method 1: Enclose the string you want to separate on multiple lines with single quotes instead of double quotes:
echo 'Usage:
./prog -v version
-h help
-x ....'
Output:
Usage:
./prog -v version
-h help
-x ....
Explanation:
Note that everything inside single quotes:
will not be expanded by bash (so you cannot use variables such as $var inside)
are interpreted literally by echo (including escaped chars, unless you use echo -e)
Method 2 - Updated for indented use inside a method: If you just have 1 long string that you'd like to break down into multiple lines in your code for better readability, you can use double quotes with the \ notation:
print_help() {
{
echo \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit,"\
"sed do eiusmod tempor incididunt ut labore et dolore magna"\
"aliqua. Ut enim ad minim veniam, quis nostrud exercitation"\
"ullamco laboris nisi ut aliquip ex ea commodo consequat."\
"Duis aute irure dolor in reprehenderit in voluptate velit"
}
print_help
Output:
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit
Explanation:
The \ character, when used as the very last character of a line in shell script, means line continuation (i.e. think of it as "hey! there's more stuff coming for this current command, don't execute it yet until you've read all of it!")
Personally, I prefer the 2nd route because you can use echo -e and escape chars (\n) for more fine-grained control over what exactly gets output =)
There is an ugly hack with cat (assuming your shell is /bin/sh):
cat <<EOS
./prog -v version
-h help
-x ....
EOS
It should be possible to do better ...
EDIT: use echo with '...' instead of cat, sorry for the misleading answer.
Here are two additional methods;
Use echo -e to interpret \n newlines and join them using \ for line continuation
echo -e "Usage:\n" \
"./prog -v version\n" \
" -h help\n" \
" -x ...."
Use sed to print out help from an anonymous Here-Document
#!/bin/bash
:<<-PRINT_HELP_DOC
Usage:
./prog -v version
-h help
-x ....
PRINT_HELP_DOC
print_help()
{
# print lines 3 to 6
sed -n '3,6p' "$0"
}

Resources