Samuel Tan
Samuel Tan

Reputation: 1750

Copying files in multiple subdirectories in the Linux command line

Let's say I have the following subdirectories

./a/, ./b/, ./c/, ... 

That is, in my current working directory are these subdirectories a/, b/ and c/, and in each of these subdirectories are files. In directory a/ is the file a.in, in directory b/ is the file b.in and so forth.

I now want to copy each .in file to a .out file, that is, a.in to a.out and b.in to b.out, and I want them to reside in the directories they were copied from. So a.out will be found in directory a/.

I've tried various different approaches, such as

find ./ -name '*.in'|cp * *.out

which doesn't work because it thinks *.out is a directory. Also tried

ls -d */ | cd; cp *.in *.out

but it that would list the subdirectories, go into each one of them, but won't let cp do it's work (which still doesn't work)

The

find ./ -name '*.in'

command works fine. Is there a way to pipe arguments to an assignment operator? E.g.

find ./ -name '*.in'| assign filename=|cp filename filename.out

where assign filename= gives filename the value of each .in file. In fact, it would be even better if the assignment could get rid of the .in file extension, then instead of getting a.in.out we would get the preferred a.out

Thank you for your time.

Upvotes: 2

Views: 7154

Answers (3)

John Zwinck
John Zwinck

Reputation: 249123

Let the shell help you out:

find . -name '*.in' | while read old; do
    new=${old%.in}.out # strips the .in and adds .out
    cp "$old" "$new"
done

I just took the find command you said works and let bash read its output one filename at a time. So the bash while loop gets the filenames one at a time, does a little substitution, and a straight copy. Nice and easy (but not tested!).

Upvotes: 4

Moe Matar
Moe Matar

Reputation: 2054

This should do the trick!

for f in `find . -type f -name "*.in"`; do cp $f `echo $f | sed 's/in$/out/g'`; done

Upvotes: 0

Kyle Burton
Kyle Burton

Reputation: 27528

Try a for loop:

for f in */*.in; do
    cp $f ${f%.in}.out;
done

The glob should catch all the files one directory down that have a .in extension. In the cp command, it strips off the .in suffix and then appends a .out (see Variable Mangling in Bash with String Operators)

Alternatively, if you want to recurse into every subdirectory (not just 1 level deep) replace the glob with a find:

for f in $(find . -name '*.in'); do
    cp $f ${f%.in}.out;
done

Upvotes: 1

Related Questions