Home > Mobile >  How to expand $() inside find -exec command
How to expand $() inside find -exec command

Time:05-13

I have a mongodump which I want to import apparently I'm looking to do this using the find command. Something like this:

find *.bson -type f -exec echo mongoimport --db=abc --collection=$(echo '{}' | sed  s/.bson//g) {} \;

What I'm looking isn't get evaluate what I need is

mongoimport --db=abc --collection=a a.bson

but I'm getting is

mongoimport --db=abc --collection=a.bson a.bson

My version of using sed to strip the .bson suffix from '{}' isn't working. I know its not a blocker but I felt if that is possible.

Any suggestions?

CodePudding user response:

The problem twofold:

  1. Shell expansions: Before a command is executed in a shell environment, the shell (sh/bash/ksh/zsh) will perform a sequence of expansions to build up the actual command that is being executed. There are seven kinds of expansion performed: brace expansion, tilde expansion, parameter and variable expansion, command substitution, arithmetic expansion, word splitting, and pathname expansion. Hence, before the find command will be executed, it will perform all substitutions, including the command substitution located in the exec statement. Ergo, the command is equivalent to:

    $ find *.bson -type f -exec echo mongoimport --db=abc --collection={} {} \;
    

    A way forward would be to prohibit the command substitution by using single-quotes, however this leads to problem two.

  2. find's exec statement is limited: The command that -exec can execute is limited to an external utility with optional arguments. Various shell features are therefor not recognized. To use shell built-ins, functions, conditionals, pipelines, redirections etc. directly with -exec is not possible, unless wrapped in something like a sh -c child shell.

Hence the answer would be something in the line of:

$ find *.bson -type f -exec /usr/bin/sh -c 'echo mongoimport --db=abc --collection=$(echo {} | sed  s/.bson//g) {}' \;

CodePudding user response:

Suggesting different strategy to this problem.

Use find with option -printf to prepare your commands.

The result will be list of commands to execute (command per line).

After inspecting and testing the commands, save find command output into a file and run the file (as a bash script).

Or just run directly into bash command.

1. find result inspection:

find . -type f -name "*.bson" -printf "mongoimport --db=abc --collection=%f %f\n" | sed s/.bson//

Notice sed replacement only on first .bson match. Do not use g option.

2. Run processed and inspected find output.

 bash <<< $(find . -type f -name "*.bson" -printf "mongoimport --db=abc --collection=%f %f\n" | sed s/.bson//)
  • Related