Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am using sed to do a bunch of changes to files. I think the question is relevant for any operation that want to iterate through files that match a pattern and include subdirectories both in the original file search recursion AND (i.e. creating them to replicate the structure) in the file creation output

I initially get the files with

mkdir -p _seded
for file in *_spec.rb
  cat $file
  ... a bunch of seds
  > _seded $file

How can I get the files plus subdirectories of files that match the pattern?

For instance if I have


then I should get:


Note: directories subex2 and subex4 should not be created as they would be empty.

I tried:

mkdir -p _seded
find . -name '*_spec.rb' | xargs cat |
  sed -e '[/pattern/replace code]' > _seded/$file

but got errors like:

$ ./convert_should_to_expect.sh 
./convert_should_to_expect.sh: line 5: _seded/: Is a directory
xargs: cat: terminated by signal 13
now doing its !!!
sed: couldn't edit _seded/: not a regular file
awk: cmd. line:1: fatal: cannot open file `_seded/' for reading (Is a directory)
mv: `_seded/tmp' and `_seded/tmp' are the same file
sed: couldn't edit _seded/: not a regular file
sed: couldn't edit _seded/: not a regular file
share|improve this question
up vote 2 down vote accepted

you could do something like this:

cd spec
find . -type f -name '*_spec.rb' | while read file; do
    mkdir -p ../_seded/"${file%/*}"
    cat "$file" | sed ... > ../_seded/"$file"

${file%/*} will cut off the filename portion of $file, so that it can be used in making the output directory in the mkdir command

share|improve this answer
Looking good. What about the final > - will that 'preserve' the directory structure for the _seded output files? Also where is $file now being defined (I also got stuck on that). – Michael Durrant Nov 2 '13 at 15:58
The while read file will fill the variable file with an output line from the find command, looping over the lines. As the output of find contains the path, the filename after > will contain that path too. You could put an echo in front of the commands inside the while loop and adjust the quoting to see what happens. – Michael Suelmann Nov 2 '13 at 16:03
Yup, that's good. Only change for me was to remove the ../'s but that's my preference for file location. Otherwise looks great. Thanks! – Michael Durrant Nov 2 '13 at 17:06
OK, I added in the ../ that you showed eventually as it creates a parallel structure so that any requires are at the 'same point' in the directory tree. – Michael Durrant Nov 3 '13 at 15:51

This is untested code! The idea here is to give you the logic I think you should follow. This does not include subdirectories, but at least it won't create a lot of empty files like your sample code and it has some syntax correction.

The for loop can be improved with something like a grep or a find statement to include subdirs, but it would take me some time to figure that out. Maybe somebody knows off the top of their head?

mkdir -p _seded
TMPFILE=/var/tmp/sedtmp$$$    # Someone can help me with the syntax for a unique file here. 
for file in *_spec.rb
  cat $file
  ... a bunch of seds >> $TMPFILE    # Each with this addition after it.
  COUNT=`wc -l $TMPFILE`
  if [ COUNT -gt 0 ]
     cp $TMPFILE _seded/$file   
share|improve this answer
+1 I used Michael's approach but thanks for this approach too! – Michael Durrant Nov 2 '13 at 17:07

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.