How to check if string begins with a square bracked in bash - bash

I need to go through my ini file and check if the line begins with a bracket, to figure out that the new config has started. Is there a way of checking this in bash? I tried
line="[test]"
if [[ "$line" =~ [.* ]]; then
echo "Got it!"
else
echo "Nothing found"
fi
but it doesn't work for me. I presume that the bracket needs to be somehow escaped, but I can't find any info as to how. Any help will be much appreciated.

To do this, you should backslash the special character [, so :
line='[test]'
if [[ $line =~ ^\[ ]]; then
echo "Got it!"
else
echo "Nothing found"
fi
EXPLANATIONS
[ is the starting character to opening a REGEX class, like [0-9]
quotes are needed everywhere but not inside bash [[ ]] tests

It's terrible to use a regexp for that! please use a bash glob instead:
if [[ $line = [* ]]; then
echo 'Got it!'
else
echo "Nothing found"
fi
Hope this helps use bash more efficiently.

Related

Bash - Comparing a string to an array that contains wildcards?

I have an array of possible file extensions, which contains some wild cards e.g.:
FILETYPES=("DBG" "MSG" "OUT" "output*.txt")
I also have a list of files, which I am grabbing the file extension from. I then need to compare the extension with the array of file extensions.
I have tried:
if [[ ${EXTENSION} =~ "${FILETYPES[*]}" ]]; then
echo "file found"
fi
if [[ ${EXTENSION} == "${FILETYPES[*]}" ]]; then
echo "file found"
fi
and
if [[ ${EXTENSION} =~ "${FILETYPES[*]}" ]]; then
echo "file found"
fi
But to no avail
I tried:
if [[ "${FILETYPES[*]}" =~ ${EXTENSION} ]]; then
echo "file found"
fi
However, it ended up comparing "txt" to "output*.txt" and concluding it was a match.
FILETYPES=("DBG" "MSG" "OUT" "output*.txt") First of all, avoid ALL_CAPS variable names except if these are meant as global environment variables.
"output*.txt": is ok as a globing pattern, for bash test [[ $variable == output*.txt ]] for example. But for Regex matching it needs a different syntax like [[ $variable =~ output.*\.txt ]]
"${FILETYPES[*]}": Expanding this array into a single_string was mostly a good approach, but it needs clever use of the IFS environment variable to help it expands into a Regex. Something like IFS='|' regex_fragment="(${array[*]})", so that each array entry will be expanded, separated by a pipe | and enclosed in parenthesis as (entry1|entry2|...).
Here is an implementation you could use:
textscript.sh
#!/usr/bin/env bash
extensions_regexes=("DBG" "MSG" "OUT" "output.*\.txt")
# Expands the extensions regexes into a proper regex string
IFS='|' regex=".*\.(${extensions_regexes[*]})"
# Prints the regex for debug purposes
printf %s\\n "$regex"
# Iterate all filenames passed as argument to the script
for filename; do
# Compare the filename with the regex
if [[ $filename =~ $regex ]]; then
printf 'file found: %s \n' "$filename"
fi
done
Sample usage:
$ touch foobar.MSG foobar.output.txt
$ bash testscript.sh *
.*\.(DBG|MSG|OUT|output.*\.txt)
file found: foobar.MSG
file found: foobar.output.txt
You cannot directly compare a string with an array. Would you please try something like:
filetypes=("DBG" "MSG" "OUT" "output*.txt")
extension="MSG" # example
match=0
for type in "${filetypes[#]}"; do
if [[ $extension = $type ]]; then
match=1
break
fi
done
echo "$match"
You can save looping with regex:
pat="^(DBG|MSG|OUT|output.*\.txt)$"
extension="output_foo.txt" # example
match=0
if [[ $extension =~ $pat ]]; then
match=1
fi
echo "$match"
Please note the expressions of regex differ from wildcards for globbing.
As a side note, we conventionally do not use uppercases for user variables to avoid conflicts with system variables.

Shell If else with regex

I am using shell to simple String regex match. Here is my shell
#!/bin/sh
MSG="ANK"
PATTERN="([A-Z]{3,5}[-][0-9]{2,5})"
if [ "$MSG" =~ "$PATTERN" ]; then
echo "MATCHED";
else
echo "not";
fi
It is giving error
abc.sh: 6: [: ANK: unexpected operator
How should I fix this?
Making the changes proposed by several contributors in the comments yields:
#!/bin/bash
MSG="ANK"
PATTERN="([A-Z]{3,5}[-][0-9]{2,5})"
if [[ "$MSG" =~ $PATTERN ]]; then
echo "MATCHED";
else
echo "not";
fi
Note the change to bash, the change to [[ and removal of the quotation marks around $PATTERN.

Does glob work differently with [[ ]] vs [ ] in Bash?

I have the file $HOME/foo/foo.mov
if [[ -f $HOME/**/*.mov ]]; then
echo "file is there" else
echo "file is not there"
fi
echoes "file is not there". whereas,
if [ -f $HOME/**/*.mov ]]; then
echo "file is there" else
echo "file is not there"
fi
echoes "file there".
Why is the difference between [[ ]] and [ ]?
Arguments to the [ command are subject to pathname expansion; the words used inside [[ ... ]] are not.
If you are getting file is there, I suspect you have exactly one file that matches the pattern. Otherwise, you would have too many arguments for -f, or the pattern would be treated as a literal string that does not name an existing file.

linux - "read -p" numbers [0-9] and "_" as imput

This time Bash question.
I am doing a script that will require user input "read -p".
The problem is that file name is in that format: vNN_NN_nn_nn_nn.zip. For example v3_11_1_2.zip or v_1_1_1_1_22.zip
I can add into script "v" to be up front - no problem.
The problem is how to read only [0-9] and [_] as a input parameter.
I tried all combinations and no success.
read -p "Please enter file name like 1_2_03_04: " filename
if [ ! $filename =~ ^[0-9]+$ ] || [! $zip =~ ^[_]+$ ]; then
echo "Filename is not valid"
else
echo "filename is $filename"
fi
No success so far. How that can be done?
Thank you.
There are a couple of changes I would make. First, be sure to use [[...]] rather than [...], as the former is BASH, and the later is just sh. The regex syntax is not just sh.
Next, you'll want to include both checks in the same regex. The [...] groups in regex can contain all the characters that you want to include.
Try this solution:
read -p "Please enter file name like 1_2_03_04: " filename
if [[ ! $filename =~ ^[0-9_]+$ ]] ; then
echo "Filename is not valid"
else
echo "filename is $filename"
fi
To support your format of filenames, I suggest using this regex:
re='^v[0-9]*(_[0-9]+)+$'
read -p "Please enter file name like v1_2_03_04: " file
[[ $file =~ $re ]] && echo "$file is valid" || echo "$file is not valid"
This will not allow weird looking filenames such as v____ or v12____ or v12_1_
RegEx Demo

Why does this if statement give me an error

Can someone explain why this simple bash script:
#!/bin/bash
myvar="Hello"
if [[ -z "$myvar" ]]; then
# echo "It's an unfilled string"
else
echo "It's a filled string!"
fi
gives me the error
./testscript: line 7: syntax error near unexpected token `else'
./testscript: line 7: `else'
However, if I remove the comment on the echo line, the script runs fine. Obviously, there is an issue with having commented lines within empty if statements. This this in mind, how do I fix it so I can have an empty if statement with comments?
There are no statements between then and else, so this is a syntax error. If you really want to do nothing in the if branch, then you can use a : (or true) as a placeholder:
#!/bin/bash
myvar="Hello"
if [[ -z "$myvar" ]]; then
# echo "It's an unfilled string"
:
else
echo "It's a filled string!"
fi
Better yet, reverse your logic:
#!/bin/bash
myvar="Hello"
if [[ -n "$myvar" ]]; then
echo "It's a filled string!"
fi
This is the way not to use if else statement.
#!/bin/bash
myvar="Hello"
[[ -n "$myvar" ]] && echo "It's a filled string!"
Also you can use this.
#!/bin/bash
myvar="Hello"
[[ -z "$myvar" ]] || echo "It's a filled string!"

Resources