1

I have the following script:

#!/bin/sh
cd $2
ls *.$1 | wc -l

I run it with: ./myct java test

where java and test are parameters which I pass

In general, I recently started to learn shell scripting and I like to play around with it, so I was wondering if it's possible to make this script even shorter?

Thanks

kvantour
  • 25,269
  • 4
  • 47
  • 72
Mike L
  • 51
  • 4
  • 3
    These questions are better suited for [codereview.se]. And to be blunt: No. Your goal should never be to make code as short as possible, but to make it as readable as possible. – MechMK1 Dec 26 '17 at 13:29
  • ```#!/bin/sh ls ${2}/*.$1 | wc -l``` – Viktor Khilin Dec 26 '17 at 13:30
  • thank you! what is the reason for curly brackets though? cant I just write $2? – Mike L Dec 26 '17 at 13:36
  • @MikeL https://stackoverflow.com/questions/18135451/what-is-the-difference-between-var-var-and-var-in-the-bash-shell here you can find a good answer about brackets and quotes near variables. – Viktor Khilin Dec 26 '17 at 13:38
  • The curly brackets are doing nothing useful, but all shell variables/positional parameters must be quoted `ls "$2"/*."$1"` unless you have a specific purpose in mind by leaving them unquoted and fully understand all of the implications and caveats. See also http://mywiki.wooledge.org/ParsingLs for why you shouldn't be doing this at all though. FInally - don't name files or directories `test` as that's the name of a builtin command. – Ed Morton Dec 26 '17 at 14:03

2 Answers2

1

Your current approach will fail when file names contain newlines (see http://mywiki.wooledge.org/ParsingLs) and/or your args contain globbing characters (google quoting shell variables) or your directory is empty (google nullglob) or doesn't exist or... One robust way to get a count of files with a given extension in the current directory using bash would be:

shopt -s nullglob
arr=( "$2"/*."$1" )
echo "${#arr[@]}"

For example:

$ ls tmp
 1.java   2.java  'a'$'\n''b.java'

$ cat tst.sh
echo "Wrong:"
ls $2/*.$1|wc -l

echo "Right:"
shopt -s nullglob
arr=( "$2"/*."$1" )
echo "${#arr[@]}"

$ ./tst.sh java tmp
Wrong:
4
Right:
3
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
-2

This is as short as I know how to make it:

#!/bin/sh
ls $2/*.$1|wc -l

However, I recommend you focus on reliability (checking for valid input) and maintainability (writing for clarity) instead of maximum terseness. Consider what should happen if no arguments are provided, for example; you might want to display a help message instead of an error message. This script also fails if an argument has spaces in it.

Mike Slinn
  • 7,705
  • 5
  • 51
  • 85
  • Well, I'm still thinking it could be hidden files inside of the folder, so `ls -a` instead of `ls` is better, imho. – Viktor Khilin Dec 26 '17 at 13:54
  • OP did not mention this requirement. He merely wanted something similar, but shorter. – Mike Slinn Dec 26 '17 at 13:58
  • It would also fail if the file names in the target directory contained newlines or if the script arguments contained globbing characters and it would produce error messages if no files matched or .... I know the OP asked for a way to make the existing script briefer but he needs to understand that what he started with (and so any briefer version of it) is simply not a reasonable approach. – Ed Morton Dec 26 '17 at 14:42
  • I can think of many reasons why this might fail. The question was for the shortest program (like a [quine](https://en.wikipedia.org/wiki/Quine_(computing))), for learning purposes, not to make a robust program. I pointed this out, then answered the question. Expanding the scope of the question is not appropriate. – Mike Slinn Dec 26 '17 at 15:22