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 have the following file structure

|--folder1
|   |---1.markdown
|--folder2
|   |---2.markdown
|--folder3
|   |---3.markdown
...

I would like to convert the markdown -files to HTML files such that the HTML -files are created to each specific folder. For instance 1.html should be at folder1.

I can convert one markdown -file by

markdown.py-2.6 1.markdown > 1.html

So we should somehow be able to get the word before the suffix before each HTML files.

How can you convert many markdown -files to their corresponding HTML files effectively?

share|improve this question
    
If somebody know how to do the same with Python, I would be glad to see. I am not sure how you can do this find . -name "*.markdown" in Python. –  Masi Jul 24 '09 at 21:21
add comment

4 Answers 4

up vote 2 down vote accepted

The existing bash-based answers will break on files with spaces in their names, and call unnecessary external commands to boot.

Assuming bash 4+ is available (it probably is, check with bash --version), you can set globstar for recursive globbing:

shopt -s globstar
for f in ./**/*.markdown; do markdown.py-2.6 "$f" > "${f%.markdown}.html"; done

This can also be done with find; for absolute bulletproof-ness, you should use a nullbyte delimiter:

find . -name '*.markdown' -print0 | while read -d $'\0' f; do
  markdown.py-2.6 "$f" > "${f%.markdown}.html"
done

This particular problem could also be solved using find's -exec option, like so:

find . -name '*.markdown' -exec bash -c 'markdown.py-2.6 "$0" > "${0%.markdown}.html" '{}' \;

However, this is not as easy to extend to multi-line scripts.

share|improve this answer
1  
Much cleaner than the other answers! find … -exec bash -c '…' {} would also work without setting the delimiters. –  slhck Jun 8 '13 at 22:22
add comment

You can do this with a small bash script:

for i in `find . -name "*.markdown"`; do 
  markdown.py-2.6 $i > `dirname $i`/`basename -s .markdown $i`.html
done
share|improve this answer
    
Wow, I was just in the process of writing the same thing. However, that doesn't take care of putting the HTML files in the subdirectories, you'll need to use cd first or something. –  jtbandes Jul 24 '09 at 20:32
    
fixed the script to put the html files in the original directories, but I cringe at the use of dirname and basename in the same line. –  jamuraa Jul 24 '09 at 20:33
1  
It is a bit ugly — could you instead use cd `dirname $i`; markdown.py-2.6 $i > `basename -s .markdown $i`.html ? –  jtbandes Jul 24 '09 at 20:44
    
$i in this script includes the path name, so you would have to do <tt>cd dirname $i; markdown.py-2.6 basename $i > basename -s .markdown $i.html</tt> –  jamuraa Jul 24 '09 at 20:46
1  
@jtbandes: Please, put your suggestion to a separate answer. It would help me in reading your code. –  Masi Jul 24 '09 at 21:10
show 2 more comments

You will probably find it easier to do this in bash (as in, once you understand the syntax it's only one or two lines), but for the record, here is how to do it in Python. You want to use two functions os.walk, and fnmatch.fnmatch to match the files you want in each directory. It looks like this:

#!/usr/bin/env python

import os, sys
from fnmatch import fnmatch

if len(sys.argv) != 2:
    print "Usage:", sys.argv[0], "<directory>"
    sys.exit()

markdown = # <path to markdown.py>
directory = sys.argv[1]

for path, directory, files in os.walk(directory):
    for file in files:
        if fnmatch(file, "*.html"):
            html_file = "%s/%s" % (path, file)
            markdown_file = html_file.replace(".html", ".markdown")
            os.system("python %s %s > %s" % (markdown, markdown_file, html_file))

The main things to take away:

  • The os.walk function traverses a directory structure (using an generator). It returns three variables:
    • The current directory (path)
    • The list of directories found in the current directory (directories). You don't need this in this case.
    • The list of files found in the current directory (files). You do need this.
  • The fnmatch.fnmatch function takes a list of files and tells you if it matches a pattern. This is a shell "glob" pattern, and not a regular expression. You can use regular expressions here, but fnmatch is just easier for a simple case like this.

Note that you need to specify the path to the markdown script. Even better would be to not use os.system but instead to import markdown the module and call it's primary function, but this generalizes to non-Python programs. (Plus, I don't know exactly what that function would be :).

share|improve this answer
add comment

A modification of jamuraa's answer:

for i in `find . -name "*.markdown"`; do
  pushd `dirname $i`
  markdown.py-2.6 $i > `basename -s .markdown $i`.html
  popd
done
share|improve this answer
2  
Please don't use for i in $(ls) or similar. See Why you shouldn't parse the output of ls(1) for the reasons why and evilsoup's answer for a safer approach. –  slhck Jun 8 '13 at 22:26
add comment

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.