In macOS Sierra (v. 10.12.6), I have a directory containing many flat-text (.txt) files. Each file has an unhelpful name such as "untitled text 252.txt". I would like to know if it's possible to programmatically rename every file based on a code located in the first line of every file.
Every file begins with a section symbol (§
), a space, a code that always contains a period (.
), and a space. The code is usually just numeric, but occasionally there is also a trailing hyphen (-
) followed by a letter. For example: '§ 177.30 '
, or '§ 60.10-a '
.
I would like to rename every file based on its code, but reformat the code first. In short, prefix a P
, strip out the period from the code, and add a trailing .txt
. Using the examples above, the file names would be: P17730.txt
and P6010-a.txt
.
At a command prompt, I have figured out how to grep the code from each file:
grep -o '^§ [A-Za-z0-9]*\.[A-Za-z0-9\-]* ' *.txt
This returns everything from the section symbol to the trailing whitespace (e.g. '§ 130.65-a '
).
So, the remaining questions are:
P13065-a.txt
); and,You can use sed
to extract only digits from the first line (by deleting all non-digits):
$ sed -n '1 {s/[^0-9]//g; p;}' <<<"§ 177.30 "
17730
and then find
all *.txt
files, extract digits, and rename to P<digits>.txt
. Instead of in-place rename, it's safer to copy the files, renaming on fly, to a target dir:
$ mkdir -p /path/to/targetdir
$ find . -name '*.txt' -exec bash -c 'digits=$(sed -n "1{s/[^0-9]//g;p;}" "$1"); cp "$1" "/path/to/targetdir/$newname"' _ {} \;
by executing a short bash
script:
#!/bin/bash
digits=$(sed -n "1{s/[^0-9]//g;p;}" "$1")
cp "$1" "/path/to/targetdir/$newname"
for each file found by find
(and given as the first positional parameter, $1
).