In a bash script, I want to define a commandstring
that specifies options and primaries for find
, based on arguments that I pass to the script. Then I want to use exec
to invoke find
with these options and primaries.
In general, I want to be able to define any invocation of find
that I could run on the command line, and exec
it inside a subshell. And in particular, I want to be able to exclude filenames containing linefeed=LF=newline=$'\n'
.
When I invoke the sample script below with argument easy
, it prints all filenames containing whitespace, and exec
works as expected. But if I invoke it with argument hard
, then exec
does not work as expected.
As you see below, if I hard-code the command find . -name *$'\n'*
, it works as expected.
But if I put it into commandstring
, it does not. Is there some way to fix this?
I do not have a higher version of bash available, am stuck with version 3 on my macOS.
The script, called junk
:
#!/bin/bash
set -f
bash --version
if [[ ${1} = easy ]]
then
printf '***%s***\n' "${1}"
commandstring="find . -name *[[:space:]]* "
elif [[ ${1} = hard ]]
then
printf '***%s***\n' "${1}"
commandstring="find . -name *$'\n'* "
else
printf '%s\n' "first argument=${1} but must be either easy or hard."
exit 1
fi
declare -p commandstring; printf '%s\n' "commandstring=${commandstring}";
printf -- '-------------------------------\n%s\n' "hard-coded hard commandstring inside this script:"
find . -name *$'\n'*
printf -- '-------------------------------\n%s\n' "hard-coded easy commandstring inside this script:"
find . -name *[[:space:]]*
printf -- '-------------------------------\n%s\n' 'Now test exec with the commandstring, inside $( subshell )'
junk=$(
{
set -f
printf '%s\n' "Now inside subshell, will exec"
declare -p commandstring; printf '%s\n' "commandstring=${commandstring}";
exec $commandstring
} > /dev/stderr ;
)
printf '%s\n' 'got past $( subshell ); now try to exec it inside the script'
exec $commandstring
printf '%s\n' 'should never get here, because it comes after exec'
How it behaves:
> find . -type f
./easy
./newlineBEF
newlineAFT
./tabBEF tabAFT
./okay
./spaceBEF AFTspace
./zzz
> ls -lT ./*
-rw-r--r-- 1 BNW staff 10 Oct 19 20:15:36 2019 ./easy
-rw-r--r-- 1 BNW staff 11 Oct 20 12:08:24 2019 ./newlineBEF?newlineAFT
-rw-r--r-- 1 BNW staff 13 Oct 19 20:15:43 2019 ./okay
-rw-r--r-- 1 BNW staff 14 Oct 20 12:37:19 2019 ./spaceBEF AFTspace
-rw-r--r-- 1 BNW staff 10 Oct 19 20:14:01 2019 ./tabBEF?tabAFT
-rw-r--r-- 1 BNW staff 0 Feb 26 11:30:54 2019 ./zzz
> junk easy
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.
***easy***
declare -- commandstring="find . -name *[[:space:]]* "
commandstring=find . -name *[[:space:]]*
-------------------------------
hard-coded hard commandstring inside this script:
./newlineBEF
newlineAFT
-------------------------------
hard-coded easy commandstring inside this script:
./newlineBEF
newlineAFT
./tabBEF tabAFT
./spaceBEF AFTspace
-------------------------------
Now test exec with the commandstring, inside $( subshell )
Now inside subshell, will exec
declare -- commandstring="find . -name *[[:space:]]* "
commandstring=find . -name *[[:space:]]*
./newlineBEF
newlineAFT
./tabBEF tabAFT
./spaceBEF AFTspace
got past $( subshell ); now try to exec it inside the script
./newlineBEF
newlineAFT
./tabBEF tabAFT
./spaceBEF AFTspace
> junk hard
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.
***hard***
declare -- commandstring="find . -name *\$'\\n'* "
commandstring=find . -name *$'\n'*
-------------------------------
hard-coded hard commandstring inside this script:
./newlineBEF
newlineAFT
-------------------------------
hard-coded easy commandstring inside this script:
./newlineBEF
newlineAFT
./tabBEF tabAFT
./spaceBEF AFTspace
-------------------------------
Now test exec with the commandstring, inside $( subshell )
Now inside subshell, will exec
declare -- commandstring="find . -name *\$'\\n'* "
commandstring=find . -name *$'\n'*
got past $( subshell ); now try to exec it inside the script
>