Home > other >  Batch renaming a single file (always same file name) within a folder to the folder name (100s of fol
Batch renaming a single file (always same file name) within a folder to the folder name (100s of fol

Time:07-04

I'm currently trying to convert a file that is contained within my Ulysses export (= a bunch of textbundle files). So, once I export all my sheets from my Ulysses (Markdown App), I'll have the following files (slightly over 700 of them) in one folder containing e.g.:

  • Exmaple File.textbundle
  • Some random name.textbundle Another random
  • Another random name.text bundle
  • ...

This is what one of these textbundle files looks like

This is what one of these textbundle files looks like

Where I need help: I'm struggling a bit do create an Automator script, bash or whatever is easier or gets the job done (I can't program) and does the following:

Removes the extension of the textbundle file, so it becomes a folder

Once the extension is removed, the textbundle file becomes a normal folder

Once the extension is removed, the textbundle file becomes a normal folder

  1. Rename the text.md file to the folder name (e.g. Exmaple File.md based on the example from above). Keep in mind: All .md files, no matter what textbundle file is being processed, will always have the same - text.md.filename, Not sure why that's the case, but it should make it easier to script, I hope.

  2. Reverse step 1 and add the extension .textbundle back to the folder so it becomes a textbundle file again

  3. Move on to the next file e.g. Some random name.textbundle and repeat steps 1-3.

Essentially, I'll have the hundreds of textbundles files and want to have an automaton script that goes through the process (1-3), renaming the text.md contained in each textbundle file so I can cleanly import these into another program.

Anyone know how the code would need to look like?

CodePudding user response:

Suppose you have a folder with content along these lines:

$ tree -N
.
|-- name 1.textbundle
|   `-- text.md
|-- name 2.something
|   `-- text.md
|-- name 3.textbundle
|   `-- text.md
|-- name4.textbundle
|   `-- text.md
`-- name5.textbundle
    `-- text.md

5 directories, 5 files

Then a script like the following, could be used to rename those text.md files within those *.textbundle directories, along the lines of how you suggested:

#!/bin/bash

if [ $# -ne 1 ]; then
    echo "Usage: $0 <directory>" 1>&2
    exit 1
fi
if [ ! -d "$1" ]; then
    echo "$0: '$1' is not a directory" 1>&2
    exit 1
fi

find . -type d -name '*.textbundle' | \
while read dirname; do
    base=$(basename "$dirname" .textbundle)
    echo "$dirname => $base:"
    pushd "$dirname" > /dev/null
    if [ -e "text.md" ]; then
        mv "text.md" "$base.md"
        echo "    Moved $dirname/text.md => $dirname/$base.md"
    fi
    popd > /dev/null
done

It requires one parameter, the base directory of where you keep all these *.textbundle directories. So if that is in ~/Documents/ for instance, you would run it like <scriptname> ~/Documents.

Running it from the start the above example directory, it would look like this:

$ <script-name> .
./name 1.textbundle => name 1:
    Moved ./name 1.textbundle/text.md => ./name 1.textbundle/name 1.md
./name5.textbundle => name5:
    Moved ./name5.textbundle/text.md => ./name5.textbundle/name5.md
./name 3.textbundle => name 3:
    Moved ./name 3.textbundle/text.md => ./name 3.textbundle/name 3.md
./name4.textbundle => name4:
    Moved ./name4.textbundle/text.md => ./name4.textbundle/name4.md

If you run it again, it won't do any accidental damage, it just won't rename any files:

$ <script-name> .
./name 1.textbundle => name 1:
./name5.textbundle => name5:
./name 3.textbundle => name 3:
./name4.textbundle => name4:

The following script moves all those files back, in case you change your mind:

#!/bin/bash

if [ $# -ne 1 ]; then
    echo "Usage: $0 <directory>" 1>&2
    exit 1
fi
if [ ! -d "$1" ]; then
    echo "$0: '$1' is not a directory" 1>&2
    exit 1
fi

find . -type d -name '*.textbundle' | \
while read dirname; do
    base=$(basename "$dirname" .textbundle)
    echo "$dirname => $base:"
    pushd "$dirname" > /dev/null
    if [ -e "$base.md" ]; then
        mv "$base.md" "text.md"
        echo "    Moved $dirname/$base.md => $dirname/text.md"
    fi
    popd > /dev/null
done

It too takes the base directory as the (only) parameter.

$ <revert-script-name> .
./name 1.textbundle => name 1:
    Moved ./name 1.textbundle/name 1.md => ./name 1.textbundle/text.md
./name5.textbundle => name5:
    Moved ./name5.textbundle/name5.md => ./name5.textbundle/text.md
./name 3.textbundle => name 3:
    Moved ./name 3.textbundle/name 3.md => ./name 3.textbundle/text.md
./name4.textbundle => name4:
    Moved ./name4.textbundle/name4.md => ./name4.textbundle/text.md

And it too will skip the renaming if it doesn't find an appropriate *.md file.

Both scripts use find to find directory names of the required name pattern, and then visit each one of them and look for an appropriate *.md file, renaming it when found. basename is used to take the directory name and simplify it the last part of the path, minus the .textbundle extension.

  • Related