2

The goal is to find *.c files to be processed with dos2unix:

find . -name *.c | xargs dos2unix -f

In an attempt to troubleshoot the above command:

user@host:~/csim/exercise$ find . -name *.c
./6-1/dinph_3p.c
./6-1/dinph_pi.c
./9-2/lift.c
./6-4/cmptr.c
./8-7/station.c
./7-4/hire.c
./5-2/ran_test.c
./8-4/cmptrm.c
./9-5/trunked.c
./8-5/computer.c
./9-3/aloha.c
./12-3/mcpu.c
./10-5/abp_pi.c
./6-2/dinph_3p.c
./6-2/dinph_pi.c

Why is that when BASH is moved up one directory:

$ cd ..

The same command does not return at least the .c files listed above?

user@host:~/csim$ find . -name *.c
find: paths must precede expression: random.c
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec|time] [path...] [expression]
gatorback
  • 1,384
  • 23
  • 48

2 Answers2

5

When you're searching for a wildcard (e.g., *.c), then you really ought to include it in single quotes. When you moved up one directory, my guess is that you entered a directory with at least two files ending in .c, one of which was random.c. In that case, bash expanded *.c to the matching files.

Assume that the directory contained hi.c and random.c, then

find . -name *.c

Becomes:

find . -name hi.c random.c

Including *.c in single quotes will cause the shell to not expand it.

To find each .c file under ~/csim and process with dos2unix:

find ~/csim -type f -name '*.c' | xargs dos2unix -f

Andy Dalton
  • 13,993
  • 2
    Or find ~/csim -type f -name '*.c' -exec dos2unix -f {} + to avoid the pipe. – Kusalananda Jan 28 '20 at 12:56
  • @Kusalananda What is the motivation to avoid the pipe? – gatorback Jan 28 '20 at 17:08
  • 1
    @gatorback Twofold in this particular case: 1) Supports all filenames, even those with embedded newlines (could also be fixed by using find -print0 and xargs -0, if supported) and 2) Neater (i.e. my personal preference). Oh, and some xargs implementation would run the utility (dos2unix -f here) regardless of whether it gets any input or not, possibly causing an error when find doesn't find anything. – Kusalananda Jan 28 '20 at 17:15
  • @Kusalananda, it's not limited to newline here. It's newline, spc, tab (possibly other whitespace depending on locale and xargs implementation), single quote, double quote, backslash (and possibly sequences of bytes that don't form valid characters in the locale, and possibly paths longer than 255 bytes with some xargs implementations). Without -print0/-0, the output of find is not compatible with the expected input format of xargs. – Stéphane Chazelas Jan 28 '20 at 17:33
1

Adding some more explanation to that of @Andy's.

Basically find command needs a file name or a pattern, as a argument(place holder) to the -name option.

when you try to run echo *.c, in the directory that contains one or more .c files, the result would be space-separated names of those files like

$echo *.c
abc.c bcd.c

If there are no .c files in the directory then the result must be

$echo *.c
*.c

Likewise find . -name *.c in the directory that has more than 1 .c file, *.c in find gets replaced by names all .c files present in that directory(*.c is expaned as multiple arguments of the option -name). That must be something like this, find . -name abc.c bcd.c. Here the error you get occurs when find starts searching bcd.c after successful search of abc.c because -name take only one argument.(if there is only 1 .c then it gets written as result, no more search in the sub-directories takes place)

But, when there are no .c files in the directory actual meaning of * in *.c gets retained.

So, when you were in ~/csim/exercise and tried to use find to search all *.c, I think there were no *.c files in the directory where find command had run. that is why wildcard meaning of * in *.c is retained and search in the sub-directories becomes successful. After cd .., search was unsuccessful because I suspect ~/csim/ has more than 1 *.c files.

Solution is much simpler, escaping wildcard would be sufficient. Use any one of this.

find .  -name '*.c'
or
find .  -name \*.c
or
find .  -name "*.c"
Abishek J
  • 170