Not able to skip blank lines in a shell script - bash

I am reading a text file line by line and taking the count of all lines as a part of my requirement.
When there is blank line then it get messed up. I tried with if condition for [ -z "$line" ] , however not able to succeed.
Here is my current code:
countNumberOfCases() {
echo "2. Counting number of test cases -----------"
cd $SCRIPT_EXECUTION_DIR
FILE_NAME=Features
while read line || [[ -n "$line" ]]
do
TEST_CASE="$line"
if [ "${TEST_CASE:0:1}" != "#" ] ; then
cd $MVN_EXECUTION_DIR
runTestCase
fi
done < $FILE_NAME
echo " v_ToalNoOfCases : = " $v_ToalNoOfCases
}
And below is Features file
web/sprintTwo/TC_002_MultipleLoginScenario.feature
#web/sprintOne/TC_001_SendMoneyTransaction_Spec.feature
web/sprintTwo/TC_003_MultipleLoginScenario.feature
#web/sprintOne/TC_004_SendMoneyTransaction_Spec.feature
When there is blank line it wont work properly so my requirement is that if there is blank line then it should be skipped and should not get considered.

You can write your loop in a little more robust way:
#!/bin/bash
while read -r line || [[ $line ]]; do # read lines one by one
cd "$mvn_execution_dir" # make sure this is an absolute path
# or move it outside the loop unless "runTestCase" function changes the current directory
runTestCase "$line" # need to pass the argument?
done < <(sed -E '/^[[:blank:]]*$/d; /^[[:blank:]]+#/d' "$file_name") # strip blanks and comments
A few things:
get your script checked at shellcheck for common mistakes
see this post for proper variable naming convention:
Correct Bash and shell script variable capitalization
see this discussion about [ vs [[ in Bash
Test for non-zero length string in Bash: [ -n “$var” ] or [ “$var” ]
about reading lines from a text file
Looping through the content of a file in Bash

Related

How I change codes of a single txt file with a names list of csv in bash ubuntu?

I have a single txt file where there are several codes with its metadata. However, I have been seeing how to change those codes with their names.
For this I have a list in csv with two columns, where the codes are in one and the names are in the other. These are 79.
This is a draft of script I have made:
#Here, the variable "Nombre" are the values of column 1 and the variable "Codigo" are the values of column 2 of nombres_codigos.csv file
#
#Then, I have use command sed to replace values of "Codigo" with values of "Nombre" into read RAxML_bipartitions_newick.newick file
#!/bin/bash
read nombres_codigos.csv
while read -r line || [[ -n $line ]]
do
Nombre="${line%;*}"
Codigo="${line#*;}"
echo "$Nombre"
echo "$Codigo"
read RAxML_bipartitions_newick.newick
while read -r line || [ -n "$line" ]
do
if [ "$Nombre" == "$Codigo" ]
then
sed -i "s/$Nombre/$Codigo/g" RAxML_bipartitions_newick.newick
echo "reemplazar"
else
echo "no reemplazar"
fi
done
p.s: nombres_codigos.csv is like:
Nombre;Codigo
EU528205_Floripondio_A56y7;EU528205_F
FJ710459_Floripondio_ABCD;FJ710459_F
EF514777_Floripondio123;EF514777_F
EU528999_Floripondio1;EU528999_F
...
My result is:
nombres.sh: line 2: read: `nombres_codigos.csv': not a valid identifier
nombres.sh: line 21: syntax error: unexpected end of file
But I hope from the file RAxML_bipartitions_newick.newick:
((((((EU528205_F:1.0000005000176948E-6,FJ710459_F:1.0000005000176948E-6):1.0000005000176948E-6,EF514777_F:1.0000005000176948E-...
switch to this:
((((((EU528205_Floripondio_A56y7:1.0000005000176948E-6,FJ710459_Floripondio_ABCD:1.0000005000176948E-6):1.0000005000176948E-6,EF514777_Floripondio123:1.0000005000176948E-...
Could someone help me modifying this, please? Thanks very much.
I am not 100% certain what you are attempting to accomplish, but it appears you want to read each line from nombres_codigos.csv and then split the line on the semi-colon. Then you want to check if the two parts are the same (which does not make sense with the sed expression that comes next)
A directly, albeit cleaned up reformatting would be:
#!/bin/bash
while read -r line || [ -n "$line" ]
do
Nombre="${line%;*}" ## separate using bash built-in parameter expansions
Codigo="${line#*;}"
echo "$Nombre"
echo "$Codigo"
if [ "$Nombre" == "$Codigo" ]
then
sed -i "s/$Nombre/$Codigo/g" RAxML_bipartitions_newick.newick
echo "reemplazar"
else
echo "no reemplazar"
fi
done < nombres_codigos.csv
If you separate "$Nombre" and "$Codigo" and then check if they are the SAME, then ... having sed replace "$Nombre" with "$Codigo" doesn't do anything at all. (It's like replacing 'A' with 'A') Did you mean:
if [ "$Nombre" != "$Codigo" ]
That would make what the script appears to do -- consistent. (e.g. change all instances of "$Nombre" with "$Codigo" in the file RAxML_bipartitions_newick.newick) If that is the case, then just change the conditional and let me know if you have further questions.

Copy number of line composed by special character in bash

I have an exercise where I have a file and at the begin of it I have something like
#!usr/bin/bash
# tototata
#tititutu
#ttta
Hello world
Hi
Test test
#zabdazj
#this is it
And I have to take each first line starting with a # until the line where I don't have one and stock it in a variable. In case of a shebang, it has to skip it and if there's blank space between lines, it has to skip them too. We just want the comment between the shebang and the next character.
I'm new to bash and I would like to know if there's a way to do it please ?
Expected output:
# tototata
#tititutu
#ttta
Try in this easy way to better understand.
#!/bin/bash
sed 1d your_input_file | while read line;
do
check=$( echo $line | grep ^"[#;]" )
if ([ ! -z "$check" ] || [ -z "$line" ])
then
echo $line;
else
exit 1;
fi
done
This may be more correct, although your question was unclear about weather the input file had a script shebang, if the shebang had to be skipped to match your sample output, or if the input file shebang was just bogus.
It is also unclear for what to do, if the first lines of the input file are not starting with #.
You should really post your assignment's text as a reference.
Anyway here is a script that does collects first set of consecutive lines starting with a sharp # into the arr array variable.
It may not be an exact solution to your assignment (witch you should be able to solve with what your previous lessons taught you), but will get you some clues and keys to iterate reading lines from a file and testing that lines starts with a #.
#!/usr/bin/env bash
# Our variable to store parsed lines
# Is an array of strings with an entry per line
declare -a arr=()
# Iterate reading lines from the file
# while it matches Regex: ^[#]
# mean while lines starts with a sharp #
while IFS=$'\n' read -r line && [[ "$line" =~ ^[#] ]]; do
# Add line to the arr array variable
arr+=("$line")
done <a.txt
# Print each array entries with a newline
printf '%s\n' "${arr[#]}"
How about this (not tested, so you may have to debug it a bit, but my comments in the code should explain what is going on):
while read line
do
# initial is 1 one the first line, and 0 after this. When the script starts,
# the variable is undefined.
: ${initial:=1}
# Test for lines starting with #. Need to quote the hash
# so that it is not taken as comment.
if [[ $line == '#'* ]]
then
# Test for initial #!
if (( initial == 1 )) && [[ $line == '#!'* ]]
then
: # ignore it
else
echo $line # or do whatever you want to do with it
fi
fi
# stop on non-blank, non-comment line
if [[ $line != *[^\ ]* ]]
then
break
fi
initial=0 # Next line won't be an initial line
done < your_file

Read line by line from parameter file in function

I have a function with a parameter file. And I want to read it line by line.
Condition
If the lines are between <?bash and ?> then I do bash -c '$line' else I display the line.
Here my file (file):
<html><head></head><body><p>Hello
<?bash
echo "world !"
?>
</p></body></html>
Here my Bash script (bashtml):
#!/bin/bash
function generation()
{
while read line
do
if [ $line = '<?bash' ]
then
while [ $line != '?>' ]
do
bash -c '$line'
done
else
echo $line
fi
done
}
generation $file
I execute this script:
./bashhtml
I am novice in Bash script and I'm lost
I think this is what you mean. However, this code is HIGHLY DANGEROUS! Any command inserted into those bash tags would be executed under your user id. It could change your password, delete all your files, read or alter data, and so on. Don't do it!
#!/bin/bash
function generation
{
# If you don't use local (or declare) then variables are global
local file="$1" # Parameter passed to function, in a local variable
local start=False # A flag to indicate tags
local line
while read -r line
do
if [[ $line == '<?bash' ]]
then
start=True
elif [[ $line == '?>' ]]
then
start=False
elif "$start"
then
bash -c "$line" # Double quotes needed here
else
echo "$line"
fi
done < "$file" # Notice how the filename is redirected into read
}
infile="$1" # This gets the filename from the command-line
generation "$infile" # This calls the function

How to get first character of variable

I'm trying to get the first character of a variable, but I'm getting a Bad substitution error. Can anyone help me fix it?
code is:
while IFS=$'\n' read line
do
if [ ! ${line:0:1} == "#"] # Error on this line
then
eval echo "$line"
eval createSymlink $line
fi
done < /some/file.txt
Am I doing something wrong or is there a better way of doing this?
-- EDIT --
As requested - here's some sample input which is stored in /some/file.txt
$MOZ_HOME/mobile/android/chrome/content/browser.js
$MOZ_HOME/mobile/android/locales/en-US/chrome/browser.properties
$MOZ_HOME/mobile/android/components/ContentPermissionPrompt.js
To get the first character of a variable you need to say:
v="hello"
$ echo "${v:0:1}"
h
However, your code has a syntax error:
[ ! ${line:0:1} == "#"]
# ^-- missing space
So this can do the trick:
$ a="123456"
$ [ ! "${a:0:1}" == "#" ] && echo "doesnt start with #"
doesnt start with #
$ a="#123456"
$ [ ! "${a:0:1}" == "#" ] && echo "doesnt start with #"
$
Also it can be done like this:
$ a="#123456"
$ [ "$(expr substr $a 1 1)" != "#" ] && echo "does not start with #"
$
$ a="123456"
$ [ "$(expr substr $a 1 1)" != "#" ] && echo "does not start with #"
does not start with #
Update
Based on your update, this works to me:
while IFS=$'\n' read line
do
echo $line
if [ ! "${line:0:1}" == "#" ] # Error on this line
then
eval echo "$line"
eval createSymlink $line
fi
done < file
Adding the missing space (as suggested in fedorqui's answer ;) ) works for me.
An alternative method/syntax
Here's what I would do in Bash if I want to check the first character of a string
if [[ $line != "#"* ]]
On the right hand side of ==, the quoted part is treated literally whereas * is a wildcard for any sequence of character.
For more information, see the last part of Conditional Constructs of Bash reference manual:
When the ‘==’ and ‘!=’ operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below in Pattern Matching
Checking that you're using the right shell
If you are getting errors such as "Bad substitution error" and "[[: not found" (see comment) even though your syntax is fine (and works fine for others), it might indicate that you are using the wrong shell (i.e. not Bash).
So to make sure you are using Bash to run the script, either
make the script executable and use an appropriate shebang e.g. #!/bin/bash
or execute it via bash my_script
Also note that sh is not necessarily bash, sometimes it can be dash (e.g. in Ubuntu) or just plain ol' Bourne shell.
Try this:
while IFS=$'\n' read line
do
if ! [ "${line:0:1}" = "#" ]; then
eval echo "$line"
eval createSymlink $line
fi
done < /some/file.txt
or you can use the following for your if syntax:
if [[ ! ${line:0:1} == "#" ]]; then
TIMTOWTDI ^^
while IFS='' read -r line
do
case "${line}" in
"#"*) echo "${line}"
;;
*) createSymlink ${line}
;;
esac
done < /some/file.txt
Note: I dropped the eval, which could be needed in some (rare!) cases (and are dangerous usually).
Note2: I added a "safer" IFS & read (-r, raw) but you can revert to your own if it is better suited. Note that it still reads line by line.
Note3: I took the habit of using always ${var} instead of $var ... works for me (easy to find out vars in complex text, and easy to see where they begin and end at all times) but not necessary here.
Note4: you can also change the test to : *"#"*) if some of the (comments?) lines can have spaces or tabs before the '#' (and none of the symlink lines does contain a '#')

How to check if a line from a file is empty with bash

I have a while loop which reads lines from a file using read line.
Then I want to check if the line is empty or not, how can I do it?
I already found questions about lines with space or about a variable in this site.
You can use the test:
[ -z "$line" ]
From the bash man page:
-z string
True if the length of string is zero.
The -n operator checks if a string is not empty:
while read line
do
if [ -n "$line" ]
echo $line
fi
done < file.txt
If you'd want to exclude strings containing only whitespace, you could use bash's pattern replacement ${var//find/replacement}. For example:
if -n [ "${line//[[:space:]]/}" ]

Resources