1

I have written an executable in c++, which is designed to take input from a file, and output to stdout (which I would like to redirect to a single file). The issue is, I want to run this on all of the files in a folder, and the find command that I am using is not cooperating. The command that I am using is:

find -name files/* -exec ./stagger < {} \;

From looking at examples, it is my understanding that {} replaces the file name. However, I am getting the error:

-bash: {}: No such file or directory

I am assuming that once this is ironed out, in order to get all of the results into one file, I could simply use the pattern Command >> outputfile.txt.

Thank you for any help, and let me know if the question can be clarified.

3 Answers 3

4

The problem that you are having is that redirection is processed before the find command. You can work around this by spawning another bash process in the -exec call:

find files/* -exec bash -c '/path/to/stagger < "$1"' -- {} \;
Sign up to request clarification or add additional context in comments.

Comments

2
  1. The < operator is interpreted as a redirect by the shell prior to running the command. The shell tries redirecting input from a file named {} to find's stdin, and an error occurs if the file doesn't exist.

  2. The argument to -name is unquoted and contains a glob character. The shell applies pathname expansion and gives nonsensical arguments to find.

  3. Filenames can't contain slashes. The argument to -name can't work even if it were quoted. If GNU find is available, -path can be used to specify a glob pattern files/*, but this doesn't mean "files in directories named files", for that you need -regex. Portable solutions are harder.

  4. You need to specify one or more paths for find to start from.

Assuming what you really wanted was to have a shell perform the redirect, Here's a way with GNU find.

find . -type f -regex '.*foo/[^/]*$' -exec sh -c 'for x; do ./stagger <"$x"; done' -- {} +

This is probably the best portable way using find (-depth and -prune won't work for this):

find . -type d -name files -exec sh -c 'for x; do for y in "$x"/*; do [ -f "$y" ] && ./stagger <"$y"; done; done' -- {} +

If you're using Bash, this problem is a very good candidate for just using a globstar pattern instead of find.

#!/usr/bin/env bash
shopt -s extglob globstar nullglob

for x in **/files/*; do
    [[ -f "$x" ]] && ./stagger <"$x"
done

2 Comments

+1 for the explanation, but I am pretty sure what he wanted is what I guessed in my answer. Recursively all files and directories in the relative path files/.
@jordanm Yeah sounds like that could be. Not sure what opening a directory for reading would be useful for though.
0

Simply escape the less-than symbol, so that redirection is carried out by the find command rather than the shell it is running in:

find files/* -exec ./stagger \< {} \;

4 Comments

For some reason, I am getting an illegal option error on this one."find: illegal option -- n find: illegal option -- a find: illegal option -- m find: illegal option -- e "
The -name option isn't valid in this context, so I've removed it.
This will not work, this is just going to pass two arguments to the ./stagger program, namely the literal < and the filename. In order for file redirection to work, the shell has to do it (if the program isn't capable of doing it itself), and the shell has to do it after the find command runs, not before. jordanm's answer does this properly.
Perhaps it's a peculiarity of Cygwin then, but this is working for me. I'll try it out on a Linux system later to see.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.