Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I'm on OS X, and I have a folder that contains a number of subfolders. There are two things I want to do. The first is to ensure that each subfolder has a file in it of the form [subfolder-name].grade.xml, then I need to search and replace within the appropriate file to make a couple of changes.

For the second part, I know how to use sed on an individual file to do what I need to, but I'm having the problem of verifying that the file is there, and then running the command on it. Any tips on doing this would be appreciated.

Note: I don't necessarily need a full answer, especially since I'm trying to learn here. A pointer in the right direction would be nice though.

(I realize that there may be better ways than the command line to accomplish this, but I've needed and will in the future need to do similar things on other Unix-based systems, so I'd rather know :)

share|improve this question
    
I might be able to give you a better answer if you make your question clearer :-) –  ℝaphink Dec 27 '09 at 22:07
    
Realized that I had formatted the name of the xml file in a way that made half of it not show up. Sorry about that! :) –  Dan G Dec 27 '09 at 22:36

2 Answers 2

up vote 1 down vote accepted
#!/bin/bash

# Get directory name from argument, default is . 
DIR=${1:-.}

# For each subfolder in DIR (maxdepth limits to one level in depth)
find "${DIR}" -maxdepth 1 -type d | while read dir; do
    # Check that there is a file called $dir.grade.xml in this dir
    dirname=$(basename "${dir}")
    gradefile="${dirname}"/"${dirname}".grade.xml
    if [ -e "${gradefile}" ]; then
          sed -i .bak "s/foo/bar/g" "${gradefile}"
    else
       echo "Warning: ${dir} does not contain ${gradefile}"
    fi done

Minor tweaks around Raphink's framework.

Key points:

  • check directly for file existence with [ -e filename ] rather than running ls
  • put all variables in ${variablename}; often not strictly neccessary, but avoids ambiguity (${variablename} and ${variable}name are clearly distinct, $variablename could mean either)
  • pass an extension to sed to make backup files. This is both good practice (in case your munging goes wrong), and, on OSX, mandatory (raphink's version interprets s/foo/bar/g as being the extension you want on the backup files, then tries to parse the filename as a command.
  • Okay, I lied, it's not actually mandatory - you could use sed -i "" "s/foo/bar/g" ${gradefile} to pass an empty extension, which would cause sed not make a backup.
share|improve this answer
    
It's always a good idea to quote variables that contain filenames. It's better to avoid backticks and use $() instead. –  Dennis Williamson Dec 28 '09 at 4:39
    
Edited to use $() instead of ``, and to quote variable that contain filenames, because Dennis is correct. –  James Polley Dec 28 '09 at 5:33

OK, you need to make a script for that. I'll pick bash for it.

#!/bin/bash

# Get directory name from argument, default is .
DIR=${1:-.}

# For each subfolder in DIR (maxdepth limits to one level in depth)
find $DIR -maxdepth 1 -type d | while read dir; do
    # Check that there is a file called *.xml in this dir
    if ls $dir/*.xml &>/dev/null; then
       # Loop through xml files found in $dir
       #   or do you actually need to check that there is only ONE file?
       for xmlfile in $dir/*xml; do
          # Do whatever treatment with sed you wish to do
          sed -i 's/foo/bar/g' $xmlfile
       done
    else
       echo "Warning: $dir does not have a *xml file in it"
    fi
done

Save that file as a .sh script, then run

$ chown +x yourscript.sh
$ ./yourscript.sh /path/to/dir # Path is optional, defaults to .
share|improve this answer

Your Answer

 
discard

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.