0
#!/bin/bash
pat="'*.ab' -o -name '*.bc'"
open="\("
close="\)"
path=path

find $path -type f $open -name $pat $close

Above code doesn't show any output for find. Do help

Arjun
  • 13

3 Answers3

2

You're using the wrong type of variable, and forgetting to quote them.

Here, you need an array to store more than one argument:

#! /bin/bash -
pat=('*.ab' -o -name '*.bc')
open='('
close=')'
path=path

find "$path" -type f "$open" -name "${pat[@]}" "$close"

Note that it's a *.ab and ( argument you want to pass to find, not '*.ab' or \(. Those quotes and backslash are part of the shell syntax.

That's only if you wanted to build a shell command line, for instance to pass to eval for the shell to evaluate it that you would do:

#! /bin/bash -
pat="'*.ab' -o -name '*.bc'"
open="\("
close="\)"
path=path

eval 'find "$path" -type f '"$open -name $pat $close"

For the shell to then evaluate:

find "$path" -type f \( -name '*.ab' -o -name '*.bc \)

Which as above results in find being called with these arguments:

  • find
  • path (content of $path)
  • -type
  • f
  • (
  • *.ab
  • -o
  • -name
  • *.bc
  • )
  • eval find "$path" \( $expression \) works. That is, you need to eval the string. – go2null Sep 14 '19 at 12:05
  • 1
    That would be wrong and dangerous in the general case as $expression is not quoted and the expansion of $path (as opposed to a literal "$path" string) would be passed to eval (making it a command injection vulnerability for arbitrary values of $path). Note how I'm careful to pass "$path" inside single quotes and $pat inside double quotes. – Stéphane Chazelas Sep 14 '19 at 12:26
2
pat="'*.ab' -o -name '*.bc'"
find $path -type f $open -name $pat $close

This doesn't do what you want: the quotes within the variable pat aren't taken as quotes, but as literal characters. After $pat is expanded, it's wordsplit, resulting in the words '*.ab', -o, -name and '*.bc', with the single quotes still intact. So unless you have filenames with single quotes within them, this will not match.

path=path

This sets the variable path to the literal string path, but I suppose this was just a placeholder.

open="\("
close="\)"

These put literal backslashes in the variables, and find should probably complain as it gets an argument of \(. It's enough to quote the parenthesis once, so either open="(" or open=\(

If you need to build a list of expressions for find, use a shell with arrays (Bash or almost anything but plain sh):

args=()  
args+=( -name "*.ab" )
args+=( -or -name "*.bc" ) 

find ... \( "${args[@]}" \)

Wrap the array-building in a loop as necessary.

ilkkachu
  • 138,973
0

Use straightforward approach (instead of playing with variables):

find $path -type f -name "*.ab" -o \( -name "*.bc" \)