Hello,
What’s the difference when we create a child shell using bash on command line and then execute commands in this shell as its childs
and
When we do bash –c and give commands in ‘..’.
First one I know creates a child shell, but do bash –c also creates a child shell or subshell.
----------------------------------------------------------
And relating to this... (actually this was the one which enabled the above question),
How find with exec is able to pass {} inside the bash –c directly to the command later executes.
e.g. find . –name “myfile” –type f –exec bash –c 'cat {}' \ ;
I mean we pass {} to any child command created via exec (e.g. exec grep “text” {}) as arguments which is usual, but to pass inside this created child is unusual and unreasoned to me.
I suppose this would be a basic one which I don’t know
bash -c 'script' passes the script in the argument. There might be a limit in the argument size, so in general prefer reading the script as stdin i.e. bash scriptfile or bash < scriptfile
Not to speak of the escape overhead when run from a shell, e.g. a ' character.
Do not use the unsafe
find . –name “myfile” –type f –exec bash –c 'cat {}' \;
Safer is
find . –name “myfile” –type f –exec bash –c 'cat "{}" ' \;
but still not good style, and not all find versions substitute the {} within a string.
Better use arguments:
find . –name “myfile” –type f –exec bash –c 'cat "$1" ' scriptname.sh {} \;
where scriptname.sh goes to "$0"
I don't like the trick
find . –name “myfile” –type f –exec bash –c 'cat "$0" ' {} \;
Passing lots of arguments to few forks of bash is faster:
find . –name “myfile” –type f –exec bash –c '
for arg
do
cat "$arg"
done
' scriptname.sh {} +
(for arg is short for for arg in "$@")
And here, since cat itself takes multiple arguments, you can do
find . –name “myfile” –type f –exec bash –c '
cat "$@"
' scriptname.sh {} +
Hi,
That were the needful pointers to refine the find with args and that I can only learn from experienced like yourself and the community. Have my appreciation and love for that 
Apart from args, my point of confusion was that how find while making child (i.e. bash -c) is passing {} , down the level below to its child(i.e. cat). I am taking cat to be at level still below bash -c, or may be I am incorrect in that.
find
|
|
bash -c (child) [ {} is usual to be passed]
|
|
cat [ {} cannot be directly used with cat, but find allows it. How ?]
Does bash -c and cat are separate childs (2 clone) OR are executing in same space, so as to use {} in cat (same execve)
Hope..I am able to explain it clearly.
find substitutes the given {} by the actual filename and forks/execs the resulting bash -c 'cat "filename"'.
Then bash forks/execs the cat "filename"
Yes ...
What was confusing me is that {} can be used inside of the argument also and this can be nested.
in grep "text" {} , its simply an argument to grep.
in bash -c 'cat $1' file1 {} , its not only within arg. of bash -c , but of cat also.
May be I am looking at it from a different angle.
Reread the most recent reply from @MadeInGermany ?
The {} is not passed to the Bash. Neither bash nor cat ever sees any {}.
find-exec substitutes all (unescaped) occurrences of {} in a copy of its own arguments, before it issues the command after -exec. It does this separately for every filename that is recognised by the selection criteria (-name, -type, date selection, etc). And it does this regardless of quotes, to avoid creating unintended word splits.
By the time the -exec is executed, there are no instances of {} at all in the command, whether that is args to the bash, or args in any child processes that get invoked.
As it happens, the issue of quoting does not arise, because the command following the -exec is not passed as text by the child. -exec will create the child process directly via a system call execve, passing all the args as null-terminated strings, which the kernel will inject into the child's main (int argc, char *argv[]) stack.
in bash -c 'cat "$1"' script.sh {} , find substitutes the {} with the filename, then bash substitutes the $1 with its arg1 i.e. the filename.
In :
bash -c 'cat "$1" ' script.sh {}
its the bash argument no 2.
but in :
bash -c 'cat {}'
is it correct to say bash's argument ..or directly find's o/p ?
And.. Paul has further explained what happens actually...its not bash's arg., but rather exec's
Thanks you both.
Thanks Paul for still more depth !
The script.sh goes to arg0 (the long command name, $0 in bash).
In
bash -c 'cat "{}"'
Some find versions e.g. GNU find) substitute the {} by the filename.
Other find version won't substitute an embedded {} and then you'd get
cat: {} not found
fileX :
#!/bin/bash
echo "arg in fileX is : $1"
$ find . -name "y1" -type f -exec ./file1 " ./file3 " ` ./file2 {} ` " " \;
o/p:
arg in file 1 is : arg in file 3 is : arg in file 2 is : ./test/y1
PS:
Here the arg of file1 i.e ./file3 "`./file2 {} `" is also in ` ` .
I was not able to put ` ` while writing here.
Wrap your code and output in ``` delimiters ("markdowns") - they may contain ` characters.
But I don't have an idea why ` characters at all. In the shell it is old style "command substitution" - new style is $( )
OK....
Is it ...?
May be I am reading an old book...and I didn't come across someone who pointed this.
Thanks.. 