How to NOT print in the output a comment in a makefile - build

I have a makefile that is like this:
install:
#somecommand
#some explanation for next command
#lastcommand
What happens is that the comment #some explanation for next command is being printed when I execute make install. How can I make a comment in a makefile that doesn't get printed? Maybe I'm looking for the unix equivalent for the windowsy echo off?
(Effectively, the opposite of this question.)

Don't indent the comment — when the line starts with a tab, it is a command that is executed by the shell (and the shell treats the comment as a comment).
Proof of concept (ss.mk):
all:
echo "This is the first command"
# This comment is echoed
# This comment is not echoed
echo "This is the second command"
Sample output:
$ make -f ss.mk
echo "This is the first command"
This is the first command
# This comment is echoed
echo "This is the second command"
This is the second command
$

I try this and it works perfectly:
test:
#echo "test 1"
## echo "test 2"
output:
$ make test
test 1
handle error:
if you want to want to assure execute all lines, shall use - at the beginning of the line that perhaps can stop your make file.
test:
#echo test1
-dkfhfwefkwef
#echo test2
#-jddhwehjwejfw
#echo test3
$ make test
test1
dkfhfwefkwef
make: dkfhfwefkwef: No such file or directory
make: [Makefile:3: test] Error 127 (ignored)
test2
make: jddhwehjwejfw: No such file or directory
make: [Makefile:5: test] Error 127 (ignored)
test3

Related

Bash add regex values to an array

I am trying to write a bash script that will take in a file and look for all values matching a regular expression, and then add those to an array.
As a first step, I wrote a script that adds all lines in the log file to an array, and echoes them. Then, I tried editing that script to search for the regular expression in the log file, which is where I got a tremendous amount of errors.
What I am trying to do is grab the value inside the brackets of the log file. Some lines in the log file contain a syntax like [23423234 s] which is a time stamp. I want to grab the values (digits, space, and the "s") inside the brackets( but not the brackets!) and add those values to an array.
My initial script is below:
#!/bin/bash
echo "STARTING SCRIPT"
getArray(){
array=()
while IFS= read -r line
do
array+=("$line")
done <"$1"
}
getArray "testlog.txt"
for e in "${array[#]}"
do
echo "$e"
done
echo "DONE SCRIPT"
The log I am looking at looks like this:
[1542053213 s] Starting Program:
-----------------------------------------
[1542053213 s] PROGRAM ERROR
ERRHAND: 1033
ERRHAND: 233545
ERRHAND: 1
[1542053213 s] Program completed!
[1542053213 s] Config File complete. Stopping!
What I am aiming to do is do something with the following pseudocode:
For each line in file{
regex = [\d\ws]
if line matches regex{
add to array
}
}
for each item in array{
echo item
}
Currently, I have edited my script to look like below:
#!/bin/bash
echo "STARTING SCRIPT"
getArray(){
array=()
while IFS= read -r line
do
if [[$line =~ [\d\ws]; then
array+=("$line");
fi
done <"$1"
}
getArray "log.txt"
for e in "${array[#]}"
do
echo "$e"
done
echo "DONE SCRIPT"
But whenever I run it, I get the following set of errors:
[jm#local Home]$ ./Parser.sh
STARTING SCRIPT
./Parser.sh: line 9: [[[1542053213: command not found
./Parser.sh: line 9: [[-----------------------------------------: command not found
./Parser.sh: line 9: [[[1542053213: command not found
./Parser.sh: line 9: [[ERRHAND:: command not found
./Parser.sh: line 9: [[ERRHAND:: command not found
./Parser.sh: line 9: [[ERRHAND:: command not found
./Parser.sh: line 9: [[[1542053213: command not found
./Parser.sh: line 9: [[: command not found
./Parser.sh: line 9: [[[1542053213: command not found
DONE SCRIPT
Any advice would be greatly appreciated. I have tried looking at other posts but none have been able to really address my problem, which is creating a proper regex for the [2342323 s] pattern, and then adding that to an array. TiA
As pointed out in the comments
if [[ is missing its closing ]].
In a regex [ is not a literal, but starts a character group. To match something like [1234 s] you have to write \[[0-9]* s\].
To extract just the number 1234 from \[1234 s\] you can use tr, sed, perl -P, or a second grep -o.
Overall, your script seems way too complicated. You can drastically simplify it. Replace the for loop by mapfile and use grep -o to extract matches. You can replace your whole script with this
mapfile -t array < <(grep -o '\[[0-9]* s\]' logfile | tr -d '[] s')
printf '%s\n' "${array[#]}"
Note that if you only want to print the matches then you don't need an array. Just the grep part would be sufficient:
grep -o '\[[0-9]* s\]' logfile | tr -d '[] s'

How to use a variable in a grep regex string in a bash script

I have a script that I am using to download EJBCA Community. They do something a little different where they put a minor version inside of a major version. For example EJBCA Community 6.10.0 has a minor version inside that folder of 6.10.1.2.
#Set build (This is actually passed as a command line argument in the main script. But for clarity I am putting it here like this.
EJBCA_BUILD=6.10.0
#Check to see if standard version URL works (no minor patched version)
STATUS="$(curl -s --head -w %{http_code} "https://sourceforge.net/projects/ejbca/files/ejbca6/ejbca_$EJBCA_BUILD/ejbca_ce_$EJBCA_BUILD.zip" -o /dev/null)"
echo $STATUS
#If it doesn't exist grep to find out what the patched version is and create $EJBCA_File with the version.
if [ $STATUS = 404 ]; then
EJBCA_FILE="$(curl -s -L "https://sourceforge.net/projects/ejbca/files/ejbca6/ejbca_$EJBCA_BUILD/ejbca_ce_$EJBCA_BUILD/" | grep -o -i "ejbca_ce_$EJBCA_BUILD_[0-9].zip" | head -n1)"
#Bring the URL together so we can download it.
EJBCA_URL=https://sourceforge.net/projects/ejbca/files/ejbca6/ejbca_$EJBCA_BUILD/$EJBCA_FILE.zip
elif [ $STATUS = 200 ]; then
# If it works then download it as is.
EJBCA_URL=https://sourceforge.net/projects/ejbca/files/ejbca6/ejbca_$EJBCA_BUILD/ejbca_ce_$EJBCA_BUILD.zip
else
echo -n "There was some other error returned from the server than 404 or 200. Exiting."
echo -n "The error code was $STATUS"
exit 1
fi
The problem I am having is specifically the grep -o -i "ejbca_ce_$EJBCA_BUILD_[0-9].zip" part. I cannot get the variable inside the regex to work. I assume this is because its parsing it incorrectly and the variable comes up empty. Any help would be greatly appreciated.
Use curly braces to ensure your variable name is what you intended, e.g., ${EJBCA_BUILD} - in this case, I suspect that because underscore (_) is a valid variable character, you are unintentionally using the variable $EJBCA_BUILD_ which is unset, so is replaced by an empty string, resulting in your grep expression being grep -o -i "ejbca_ce_[0-9].zip" which isn't what you want.
You can see this by doing a simple test in your shell:
$ EJBCA_BUILD=dummy
$ echo "ejbca_ce_$EJBCA_BUILD_[0-9].zip"
ejbca_ce_[0-9].zip
$ echo "ejbca_ce_${EJBCA_BUILD}_[0-9].zip"
ejbca_ce_dummy_[0-9].zip

How to match the regex for the below pattern?

I am trying to write a script which should work out like this below but somehow am not able to get the write way to put the syntax.
I have folders like S_12_O_319_K4me1.
While the contents are S_12_O_319_K4me1_S12816.sorted.bam in each folder.
So I wanted to write a script where my my script goes into my folder of the same name in a loop and then identifies the *.bam file and perform the operation, but I am unable to put the regex. This is what I tried:
#!/bin/bash
#$ -S /bin/bash
spp_run=/path/phantompeakqualtools/run_spp.R
bam_loc=/path/ChIP-Seq/output
samples="S_12_O_319_K27me3
S_12_O_319_K4me1
S_12_O_319_K4me3
S_12_O_319_K27ac"
for s in $samples; do
echo "Running SPP on $s ..."
Rscript $spp_run -c=$bam_loc/$s/${s}_S[[0-9]+\.sorted.bam -savp -out=$bam_loc/$s/${s}".run_spp.out"
done
I am not being able to recognize the digits with the above regex match.
Where am I getting it wrong?
Edit:
I tried below still it does not work, problem with parsing in the Rscript, but why will this be a problem
#!/bin/bash
#$ -S /bin/bash
spp_run=/path/tools/phantompeakqualtools/run_spp.R
bam_loc=/path/ChIP-Seq/output
samples="S_12_O_319_K27me3
S_12_O_319_K4me1
S_12_O_319_K4me3"
for s in $samples; do
echo "Running SPP on $s ..."
echo $bam_loc/$s/${s}_S*.sorted.bam
inbam=$bam_loc/$s/${s}_S*.sorted.bam
echo $inbam
Rscript $spp_run -c=$inbam -savp -out=$bam_loc/$s/${s}".run_spp.out"
done
echo "done"
Error
Error in parse.arguments(args) :
ChIP File:/path/ChIP-Seq/output/S_12_O_319_K27me3/S_12_O_319_K27me3_S*.sorted.bam does not exist
Execution halted
Does not recognize the file even though $inbam value is /path/ChIP-Seq/output/S_12_O_319_K27me3/S_12_O_319_K27me3_S12815.sorted.bam
You can use a regex in a find command :
export spp_run=/path/phantompeakqualtools/run_spp.R
export bam_loc=/path/ChIP-Seq/output
export dir
samples=(S_12_O_319_K27me3 S_12_O_319_K4me1 S_12_O_319_K4me3 S_12_O_319_K27ac)
for dir in ${samples[#]}; do
find . -type f -regex ".*/*${dir}_S[0-9]+\.sorted\.bam" \
-exec bash -c 'echo Rscript $spp_run -c=$bam_loc/${dir}/${1##*/} -savp -out=$bam_loc/${dir}/${dir}".run_spp.out"' _ {} \;
done
Note : just remove the echo before the Rscript if the output meets your needs.
I found answer to my query and below is the code. Not an elegant one but it works. I realized that the Rscript requires full name and full path so I just initialized the output of the echo command to a variable and passed it to the Rscript as input file argument and it gets a full path with full filename so now it recognizes the input file.
Not an elegant way but still it works for me.
#!/bin/bash
#$ -S /bin/bash
spp_run=/path/tools/phantompeakqualtools/run_spp.R
bam_loc=/path/ChIP-Seq/output
samples="S_12_O_319_K27me3
S_12_O_319_K4me1
S_12_O_319_K4me3"
for s in $samples; do
echo "Running SPP on $s ..."
echo $bam_loc/$s/${s}_S*.sorted.bam
inbam=$bam_loc/$s/${s}_S*.sorted.bam
echo $inbam
infile=`echo $inbam`
Rscript $spp_run -c=$infile -savp -out=$bam_loc/$s/${s}".run_spp.out"
done
echo "done"
Thanks everyone for the suggestions and comments. My code is not elegant but it is working so I put the answer here.

How to echo text and read input after every line of a file?

Been working on a project of my own (actually learning bash programming) and came across a step which I have been stuck for a couple of days.
I pretend to use awk to print the first line of a file, then print fields for manual completion under that line. I want that it repeats that process for every line in that file.
My script below prints all lines of the file above the list, and loops forever. It should stop at the last line.
That is what I've gotten:
while awk -F"|" 'NR' resultado.txt; do
echo "Histórico:"
read Historico
echo "Conta:"
read Conta2
echo "Valor:"
read Valor
done
Example:
Lines from the file to be processed:
LAURVOGT| 31|02/05/2015|6.1.1.01.001|2.1.1.01.005||8,100|DIVERSOS|||N||| ||S|CB|||05|||||||31,000|N|N|||0,000|
LAURVOGT| 34|03/05/2015|6.1.1.01.002|2.1.1.01.005||6,900|DIVERSOS|||N||| ||S|CB|||05|||||||34,000|N|N|||0,000|
How they should be processed:
LAURVOGT| 31|02/05/2015|6.1.1.01.001|2.1.1.01.005||8,100|DIVERSOS|||N||| ||S|CB|||05|||||||31,000|N|N|||0,000|
Historico:
(Should be able to type info, and when I'm done next "Conta" shows up below)
Conta:
(Should be able to type info, and when I'm done next "Valor" shows up below)
Valor:
(Should be able to type info, and when I'm done the command repeats all this for the next line, until the last one from the file)
Could anyone please guide me to my desired result?
This code seems to work not using Bash extensions to the read command. It works with Bash run as sh and with ksh. I wrote it before the sample data got added to the question. I'm not going to rewrite it, but the problem just got more complex.
reader.sh
while read -r line <&3
do
echo "$line" >&4
echo "Histórico: "
read -r Historico
echo "$Historico" >&4
echo "Conta: "
read -r Conta2
echo "$Conta2" >&4
echo "Valor: "
read -r Valor
echo "$Valor" >&4
done 3<resultado.txt 4>output.txt
Lots of I/O redirection. The output goes to file descriptor 4, which is pointed at the file output.txt. The file input is on file descriptor 3, coming from resultado.txt. The read command at the top of the loop redirects its standard input from file descriptor 3, which means it reads the next line of resultado.txt. The echo "Xyz: " commands in the body of the echo to the terminal (standard output). There are ways to suppress the newline after the echo, but they're shell-dependent (echo -n is one way; echo "Xyz: \c" is another). The read -r Xyz commands in the loop body read from the terminal. The echo "$Xyz" >&4 commands send the output to file descriptor 4, as does the echo "$line".
If you have Bash, you can use read -r -u 3 line instead of the read with I/O redirection. You could also use read -p 'Valor: ' -r Valor to prompt for and read the inputs.
resultado.txt
This is the first line.
This is the second line.
This is the third line.
Example run
I don't like typing, so I had a random number generator generate enough data. It does work when I use myself as the generator of the random inputs.
$ random -n 9 -F "RNG: %.2d" 0 99 | sh reader.sh
Histórico:
Conta:
Valor:
Histórico:
Conta:
Valor:
Histórico:
Conta:
Valor:
$
output.txt
This is the first line.
RNG: 66
RNG: 49
RNG: 02
This is the second line.
RNG: 18
RNG: 90
RNG: 36
This is the third line.
RNG: 56
RNG: 22
RNG: 95
Revised question
There are many fields in the input. It is not clear what you're supposed to do with the input line, or the prompted for data. If you need to edit the responses into the line, then you've got a much more fearsome job ahead.

Making quotation marks survive to a command run inside a bash script

The following code saves my_string in the file my_filename and
then checks whether pattern1 and pattern2 are in the file. The
first is; the second isn't.
#!/bin/bash
my_string="One two three four"
pattern1="two three"
pattern2="two four"
my_filename="my_temp_file"
safeGrepCommand() {
typeset command_to_run="$*"
typeset ret_code
# echo command_to_run=$command_to_run
eval $command_to_run
ret_code=$?
if [ $ret_code != 0 ]; then
printf "Pattern %s is not in the file %s.\n" "${my_pattern}" "${my_filename}"
exit $ret_code
fi
}
echo $my_string > $my_filename
grep_command1="grep --quiet ${pattern1} ${my_filename}"
safeGrepCommand "$grep_command1"
grep_command2="grep --quiet ${pattern2} ${my_filename}"
safeGrepCommand "$grep_command2"
rm -f $my_filename
I am expecting to see the output
Pattern two four is not in the file my_temp_file.
Instead I see
grep: three: No such file or directory
grep: four: No such file or directory
As you'll see if you uncomment the echo line inside the function, the problem is that the quotation marks are not seen by grep.
command_to_run=grep --quiet two three my_temp_file
command_to_run=grep --quiet two four my_temp_file
How do I get bash to pass the quotation marks to grep? Alternatively, how do I specify "two three" as a regexp with [:space] and not worry about quotation marks.
Here's one way of resending arguments in a shell function:
doit_or_complain() {
# The arguments are captured only to show how to do it. In practice,
# I would just use "${#}" to run the command.
local -a command=("$#")
"${command[#]}"
local rc=$?
if ((rc)); then
echo "The command failed" >> /dev/stderr
fi
return $rc
}
That will work with any random arguments:
doit_or_complain grep "a b" "./my file with spaces in its name"
If you want to pass a complicated command to the shell function, you should use an array:
theCommand=(grep "a b" "./my file with spaces in its name")
#...
doit_or_complain "${theCommand[#]}"
Note: The function in the OP used exit $rc if the command failed. That will exit the current shell, not just the function, which might be considered a tad unexpected, if not unsafe.
Wrap the pattern variable in double quotes as
grep_command1="grep --quiet \"${pattern1}\" \"${my_filename}\""
safeGrepCommand "$grep_command1"
grep_command2="grep --quiet \"${pattern2}\" \"${my_filename}\""
safeGrepCommand "$grep_command2"