Home > other >  Bash script jumps to else statement and not then, shows no errors
Bash script jumps to else statement and not then, shows no errors

Time:11-04

I've created a script that should read a file, then find out wether the first line has a vowel in the first word/line, and if it does, it should output only the first 10 words in the list. If not the first 15. My issue is that the script instead of showing the first 10 lines when I input a file that starts with a vowel, it shows me the first 15 wether it's starts with a vowel or not.

My script is as following:

first reads file, then puts the first word in a variable to then be checked if it starts with a vowel, then outputs into another file.

#!/bin/bash

cat file.txt | word=$(head -1 file.txt)

if [[ "$word" == '^[AaEeIiOoUu]' ]]
then head -10 file.txt > words.txt
else head -15 file.txt > words.txt 
fi 

The then statement is not acknowledged by my script, unsure why.

f.ex input file: file.txt island bus carriage train tractor

I have tried changing the == in the 2 line to be =~. I have tried removing, the else head -15 to see if I get the first 10 lines. Also spellcheck, and jdoodle shows no errors

CodePudding user response:

Problem 1

By putting the assignment to a pipeline, you run it in a subshell. Variable values don't propagate form a subshell to the parent process.

Solution

# cat file.txt | word=$(head -1 file.txt)
word=$(head -1 file.txt)

Also, this reads the first line into the variable, not the first word. To remove everything after the first space, you can use Parameter Expansion:

word=${word%% *}  # Remove everything from the first space onward.

Problem 2

The == operator expects a pattern on the right hand side, not a regex. If you use =~, a regex is expected, but quotes enforce literal meaning.

Solution

# if [[ "$word" == '^[AaEeIiOoUu]' ]]
if [[ $word == [AaEeIiOoUu]* ]]
# or
if [[ $word =~ ^[AaEeIiOoUu] ]]

Moreover, if you want to test the line contains a vowerl rather than it starts with a vowel, you have to prepend an additional asterisk to the pattern, or remove the caret from the regex:

if [[ $word == *[AaEeIiOoUu]* ]]
# or
if [[ $word =~ [AaEeIiOoUu] ]]

CodePudding user response:

A minimal fix would look like

#!/bin/bash

# avoid doubly useless cat
word=$(head -1 file.txt)

# fix regex operator and regex
if [[ "$word" =~ [AaEeIiOoUu] ]]
then head -10 file.txt > words.txt
else head -15 file.txt > words.txt 
fi 

though you might want to refactor to

if [[ "$(head -1 file.txt)" =~ [AaEeIiOoUu] ]]; then
   lines=10
else
   lines=15
fi
head -n "$lines" file.txt >words.txt

or even rewrite the whole thing in Awk:

awk 'FNR == 1 { end = ($1 ~ /[AaEeIiOoUu]/ ? 10 : 15) } 1
FNR==end { exit }' file >words.txt

Your question seems to imply that the first line contains a single word. If you really want to focus on only the first word on the line, the shell script needs to have a slightly more elaborate regex.

  • Related