1

I am trying to write a .sh script where at a certain point it checks if there are one or more files in the current directory matching *\_??\_??\_64kbs.mp3

OR, using regex ^.*\_..\_..\_64kbs\.mp3$

This is one attempt at the command:

if [ 'ls *_??_??_64kbs.mp3 2>/dev/null | wc -l ' == 0 ];
then echo "nothing";
else echo "something";
fi

I know that

'ls *_??_??_64kbs.mp3 2>/dev/null | wc -l'

in this case returns just the number 9 to the terminal, because there are 9 matches. If I remove the first '?', it then returns 0, like it should because there are no file names matching that expression. But the output of the if expression above is always "something".

EDIT: Someone asked for a complete sample file name for what I'm trying to match. Here's one:

George-1983_1A_01_64kbs.mp3
muehsi
  • 588
  • 3
  • 19

2 Answers2

1

You are clearly confusing with a glob with a regex match, * is a pure glob construct which can be used in a loop as below

fileNamePattern="*_??_??_64kbs.mp3"
for file in *.mp3; do
    [[ $file == $fileNamePattern ]] && echo "$file matches"
done 

The meaning of ? and * are different when used in a regex context, where we use .* for matching up to a part and .{} to represent any character whose occurence can be dictated by the value inside {}, for example,

fileNameRegex=".*_.{2}_.{2}_64kbs.mp3"
for file in *.mp3; do
    [[ $file =~ $fileNameRegex ]] && echo "$file matches"
done

The ~ is the bash regex operator (supported from bash version 4.0 onwards) you need to match a regex and not a glob.

Inian
  • 80,270
  • 14
  • 142
  • 161
  • Thanks for the answer, and this works, but I was clearly 'not' confusing glob with regex. You can see at the beginning of my question I suggested an equivalent regex to the glob I was using in the example. It's the same as yours except I explicitly write .. instead of .{2}, and I prefaced it with a ^ and ended it with a $. – Matthew Jendrasiak Mar 28 '17 at 07:25
  • @MatthewJendrasiak: Appreciate it! Thought with both the glob and regex approaches used, there was some confusion around. If this solved your problem, don't forget to upvote and accept it to make it helpful for future readers. – Inian Mar 28 '17 at 07:27
-1

I found a solution that seems to be working. Wrap the command in a $() instead of quotes.

if [ $(ls *_??_??_64kbs.mp3 2>/dev/null | wc -l) == 0 ];
then echo "nothing";
else echo "something";
fi

I tried something like this earlier and it didn't seem to work but there must have been a syntax error. In this case it is working.

  • This is clearly not the right way to go, Parsing output of `ls` is generally not recommended, see [Why you shouldn't parse the output of ls](http://mywiki.wooledge.org/ParsingLs) – Inian Mar 28 '17 at 07:21
  • to shed some light on the possible syntax error seems you tryed `'ls ...'` (the literal string "ls ...") `$('ls ...')` (the output of a command named "ls ....", files and therefor commands my have blanks in them) never `$(ls ...)` or `\`ls ...\`` (both work). – Samuel Kirschner Mar 28 '17 at 07:38
  • Also piping to `wc -l` is a very common antipattern. See http://www.iki.fi/era/unix/award.html#wc – tripleee Mar 28 '17 at 08:17