1

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 :)

2
  • I might be able to give you a better answer if you make your question clearer :-)
    – raphink
    Dec 27, 2009 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, 2009 at 22:36

2 Answers 2

2
#!/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.
2
  • It's always a good idea to quote variables that contain filenames. It's better to avoid backticks and use $() instead. Dec 28, 2009 at 4:39
  • Edited to use $() instead of ``, and to quote variable that contain filenames, because Dennis is correct. Dec 28, 2009 at 5:33
0

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 .

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .