-1

I want to count the number of files matching a pattern at a depth of 1, and compare it with a number, e.g. to see if I have 3 or more such files. However, I want to do this without using the if/then syntax.

i.e. something like this:

ls -1q -d *patternX* | wc -l | [ -ge 3]

I'd appreciate very much if someone could let me know if there's a way to escape using the if/then syntax. Thanks!

abra
  • 65
  • 7
  • 4
    _"I **want** to do this without using the if/then syntax"_ -- So, is there some reason to not use a construct made exactly for conditional execution if conditional execution is what you want/need to do? If you've just arbitrarily decided that the obvious solution is not acceptable, than how can we know if some other solution would also not be acceptable? – ilkkachu Apr 23 '21 at 12:54
  • 1
    As commented already, if you have any constraints (i.e., "not using ''if'"), please explain why such a constraint exists. We cannot offer much help if you provide arbitrary constraints that limit how we can help. – C. M. Apr 23 '21 at 13:30
  • @ilkkachu Thanks for commenting. I'm familiar with the if/then syntax and have used it in the past. I was curious whether the same aim could be achieved this way (piping "directly" into an inequality comparison), and therefore asked the question in the title out of pure curiosity/academic interest. – abra Apr 24 '21 at 13:01
  • @C.M. Thanks for commenting. I asked the question in the title not out of necessity, but out of pure curiosity/academic interest. I keep learning new things everyday; I wondered whether it could be done this way and thought if anyone knew, it would be someone on this site, and therefore I asked. – abra Apr 24 '21 at 13:05
  • @abra: I suggest you edit your question to indicate that, so it's up front instead of someone having to read through the comments down here. I will note, however, that your "compare it ... and **_if_** ..." statements make it very difficult to do without some kind of logic branching (i.e., using `if`), as your requirement itself has an "if". You can save the wc output to a shell variable, but without knowing more about your goal, that may be useless. (I.E., let's say you _can_ `[ $result -gt 3 ]` ... but what do you want to _do_ with the comparison? it will just be a true/false boolean value.) – C. M. Apr 25 '21 at 05:36
  • (and to add given comments posted to some answers): Just having stating it in the title is not enough. The title often only gets the attention of those who want to help, or those seeking a solution to a similar/identical problem. Then they read the body of the question to find out the full _details_--even ones already stated in the title. – C. M. Apr 25 '21 at 05:44

3 Answers3

4

You seem to want to count the number of names matching *patternX* and then test whether that is greater than or equal to three.

This is best done like so:

shopt -s nullglob

set -- *patternX*
if [ "$#" -ge 3 ]; then
    echo 'More than 2 names match the pattern'
fi

This is setting the positional parameters to the names matching the pattern. The number of matching names would be kept in $#. The nullglob option is set so that if there are no names matching, the pattern is removed completely rather than kept unexpanded.

You could also use a named array to store the matching names:

shopt -s nullglob

names=(*patternX*)
if [ "${#names[@]}" -ge 3 ]; then
    echo 'More than 2 names match the pattern'
fi

See also Why *not* parse `ls` (and what to do instead)?


Without the words if and then:

shopt -s nullglob

set -- *patternX*
[ "$#" -ge 3 ] && echo 'More than 2 names match the pattern'

A similar approach using awk:

shopt -s nullglob

awk 'BEGIN { if (ARGC > 3) print "more than 2" }' *patternX*

Note that ARGC in awk also accounts for the command name (what would be $0 in the shell).

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • Hi! Thank you, but my question specifically asks whether it is possible to do this without using the "if;then" syntax, so this isn't what I'm looking for. – abra Apr 23 '21 at 12:07
  • @abra See updated answer – Kusalananda Apr 23 '21 at 12:09
  • Thank you! Your second suggestion doesn't have "if" and "then", but it's mostly a technicality as the underlying method is similar. As I mentioned in the title, I am looking for a syntax (if possible) where I can pipe the output of a command (like wc) directly into an inequality operation. – abra Apr 23 '21 at 12:16
  • 1
    @abra The issue is that the operation that you seem to want to do, i.e. count names matching a pattern, should not generally be done with `ls` and `wc`. – Kusalananda Apr 23 '21 at 12:22
  • Tests do not read stdin, so you need something inside the test that *does* read the pipe: `echo 7 | [ $( cat ) -ge 6 ] && echo Bigger || echo Not`. – Paul_Pedant Apr 23 '21 at 12:25
  • 2
    @abra so, like `[ "$(... | wc)" -ge 3 ]`? – muru Apr 23 '21 at 12:28
  • @Paul_Pedant thanks, much closer to what I want, but I would want the command to print 0 or 1 at the end; if I cut off the " &&...." part of your suggestion, it doesn't return any output – abra Apr 23 '21 at 12:35
  • Test returns a true (0) false (1) status. `echo 7 | [ $( cat ) -ge 6 ]; echo $?`. – Paul_Pedant Apr 23 '21 at 12:39
  • 2
    @abra please edit your question and add all of these requirements. What you are asking for is not a standard feature and most of us are happy using either `if/else` or `condition && foo || bar` constructs so if you cannot use that we need to know. – terdon Apr 23 '21 at 15:16
  • @terdon the title of the question mentions all these requirements. The question is less out of necessity and more out of curiosity because it's the syntax that came first/intuitively to my mind, but I couldn't find any solutions along those lines. So I thought I'd consult the community since I'm a relative beginner and see if it's possible. I'm not necessarily asking if it's the best/most common solution. – abra Apr 24 '21 at 07:46
  • 1
    @abra So you don't need to count the number of files in a directory in a correct way, or even interested in how that should be done in a portable and idiomatic way? You're just interested in how to do something that nobody would want to do, just to see whether it's possible? – Kusalananda Apr 24 '21 at 07:49
  • @Kusalananda It's not that I'm uninterested in how to do it the correct way. I'm familiar with the if/then syntax and have used it in the past. I was curious whether the same aim could be achieved this way, and therefore asked. I assumed this was a place where questions of pure curiosity/academic interest were welcome. – abra Apr 24 '21 at 12:56
2

With zsh, you'd typically use an anonymous function such as:

()(( $# >= 3 )) *patternX*(N)

That calls an anonymous function whose body is (( $# >= 3 )) (which returns true if the number of arguments is 3 or more), with the expansion of the *patternX*(N) glob as arguments.

(N) is to enable the nullglob option for that glob so that the glob expands to nothing instead of reporting an error if there's no matching file.

A more literal answer to what you're asking could be:

ls -1q -d -- *patternX* | wc -l | xargs -IN test N -ge 3

(in any shell, but beware behaviour varies between shell when the pattern doesn't match any file).

Or:

[ "$(( $(ls -1q -d -- *patternX* | wc -l) ))" -ge 3 ]

(in any POSIX or Korn-like shell)

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
0

I find it hard to believe that this is a real world problem, but here's one solution:

ls -1q -d *patternX* | wc -l | egrep '^[3-9][0-9]*|[0-9][0-9]+' && echo JA
Ljm Dullaart
  • 4,142
  • 11
  • 26