3

In a shell script, I have a function afun that was passed a few arguments. I need another function that will help me find out if at least one of those arguments contains a given character which is not known a priori (but it could be any character like a, 9, *, \, |, /, (, [ and so on, but not space):

afun() {
  # Some commands here...
  testchar=... # here I have some logic which decides what character should be tested below
  # Now, call another function to test if any of the args to "afun"
  # contain the character in var "testchar".
  # If it does, print "Found character '$testchar' !"
}

The proposed function should be compatible at least with Bash, Dash, Ash and ZSH - because I have a script that needs to run under different Linux distros (Ubuntu, Alpine Linux) installed in Docker containers, and I don't want to declare a dependency on a specific shell interpreter since not all those containers will necessarily have it installed.

Elifarley
  • 1,310
  • 3
  • 16
  • 23
  • 3
    Bash, Dash, Ash and ZSH . That sounds like you're kidding. ;) And the question is not very clear.. – sjsam Jun 17 '16 at 18:48
  • ZSH has more features than Ash, but is it unreasonable what I'm asking? And thanks, I've fixed the variable name (it should be `testchar` instead of `c`) – Elifarley Jun 17 '16 at 18:50
  • Not unreasonable, but should be very difficult IMHO.. :( – sjsam Jun 17 '16 at 18:51
  • I have edited the question. Let me know if it still lacks clarity. – Elifarley Jun 17 '16 at 18:56
  • I believe somebody cannot come up with a useful solution because shell features vary even with different versions of the same shell. Now I cant imagine using different shells.. :( – sjsam Jun 17 '16 at 19:04
  • I have a bash specific solution for you anyways. I would be very happy if you could somehow tweak it to work with different shells.. – sjsam Jun 17 '16 at 19:06
  • 3
    @Elifarley, it's not just "more features" -- ash, bash and ksh are compliant with POSIX sh (barring caveats like bash's support for `echo -e`), whereas zsh is intentionally incompatible with the standard (in places where its maintainers decided -- with some basis in fact -- that the standard enforces bad design decisions) unless running in non-default posix mode. That's not to say that writing scripts compatible with both zsh and POSIX-compliant shells can't be done, but it does mean that it requires a bit more care than the usual (ash+bash+ksh) practice of just complying with POSIX. – Charles Duffy Jun 17 '16 at 19:23
  • 1
    BTW, `local` is not defined by POSIX -- if you're going for maximal compatibility, you'll want to do without. – Charles Duffy Jun 17 '16 at 19:26
  • The question in the title is adequately answered by the duplicate. If you need help looping over a set of strings, perhaps post a new question (but do look for duplicates first; the [Stack Overflow `bash` tag wiki](http://stackoverflow.com/tags/bash/info) contains a substantial collection of common questions. – tripleee Jun 20 '16 at 04:35

2 Answers2

4

Here's my proposed shell function:

charexists() {
  char="$1"; shift
  case "$*" in *"$char"*) return;; esac; return 1
}

And here's how you can use it:

afun() {
  # Some commands here...
  testchar=... # here I have some logic which decides what character should be tested below
  # Now, call another function to test if any of the args to "afun"
  # contain the character in var "testchar".
  # If it does, print "Found character '$testchar' !"
  charexists "$testchar" "$@" && echo "Found character '$testchar' !"
}

Here's a simple unit test:

fun2test=charexists
{ $fun2test '*' 'a*b' && printf 1 ;} ; \
{ $fun2test '*' 'a' '*' '\' 'b#c|+' '\' && printf 2 ;} ;\
{ $fun2test '\' 'a' '*' '\' 'b#c|+' '\' && printf 3 ;} ;\
{ $fun2test '*' 'ab' || printf 4 ;} ; \
{ $fun2test '*' 'a' '' '/' 'b#c|+' '\' || printf 5 ;}; echo

It should print 12345 if all 5 tests pass.

I have just tested under Bash, Dash, Ash and ZSH and all went well.

Elifarley
  • 1,310
  • 3
  • 16
  • 23
  • 1
    `charexists "$testchar" $*` -- without the `$*` quoted -- will behave badly if your list of arguments contains, say, `*` -- unless you *want* that to be expanded to a list of filenames in the current directory. – Charles Duffy Jun 17 '16 at 19:29
  • Indeed! Fixed, thanks! – Elifarley Jun 17 '16 at 19:47
-1

Below is my bash specific solution for this :

#!/bin/bash
fun()
{
  not_allowed=' ' # Charater which is not allowed
  [[ "$1" =~ $not_allowed ]] && echo "Character which is not allowed found"
}

fun "TestWithoutSpace"
fun "Test with space"
sjsam
  • 21,411
  • 5
  • 55
  • 102
  • Using the test case found in my solution, your proposed solution only prints `34`, so it fails the first 2 tests. – Elifarley Jun 17 '16 at 19:20