Note The file appears to be in "Composite Document File V2 Document" format. There are likely libraries that can read this the appropriate way.
Wild guess: Are you trying to "read" Outlook .msg
files, word/excel documents?
Use file
or see
- http://ask.libreoffice.org/en/question/13/how-do-i-get-document-information-from-the-command/
UPDATE C++ version added (see below)
A little hacking with the file told me it's a binary file and the strings are not delimited, but preceded by their length bytes. So, this bash script should work in general:
#!/bin/bash
set -e # stop on errors
for originalname in "$@"
do
# get lengths
first_len=$(od -j 2085 "$originalname" -An -t u1 -N1)
second_len=$(od -j $((2086 + $first_len)) "$originalname" -An -t u1 -N1)
# strip whitespace
read first_len second_len <<< "$first_len $second_len"
# extract the words as text
firstword=$(dd if="$originalname" bs=1 skip=2086 count=$first_len)
secondword=$(dd if="$originalname" bs=1 skip=$((2087+$first_len)) count=$second_len)
# calculate new name, using the timestamp of the file too:
newname="$firstword $secondword $(date -r "$originalname" +"%Y-%m-%d")"
# do the move (verbosely)
mv -v "$originalname" "$(dirname "$originalname")/$newname"
done
I tested it on the file you supplied:
$ ./test.sh short.zhr 2>/dev/null
`short.zhr' -> `./MyName Sirname 2013-06-11'
You gotta love UNIX philosophy :)
For your case you could just run
./test.sh somedir/AA*
C++ version
For fun I wrote a C++ version. This should be pretty easily portable.
It's actually a bit more readable (except for the part to formats the timestamp...).
#include <string>
#include <vector>
#include <fstream>
#include <ctime>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
std::string extract_string(std::istream& is) {
char len;
if (is && is.read(&len, 1)) {
std::string result(len, '\0');
is.read(&*result.begin(), len);
return result;
}
return "";
}
std::string timestamp(std::string const& fname, const char* fmt = "%Y-%m-%d")
{
struct stat sb;
if (-1 == stat(fname.c_str(), &sb))
perror("cannot get file stats");
if (struct tm* tmp = localtime(&sb.st_ctime))
{
std::string buf(200, '\0');
buf.resize(strftime(&*buf.begin(), buf.size(), fmt, tmp));
return buf;
} else
perror("localtime failed");
return "";
}
int main(int argc, const char *argv[])
{
for (int i = 1; i<argc; ++i)
{
const std::string fname(argv[i]);
std::ifstream stream(fname.c_str(), std::ios::binary);
stream.seekg(2085);
std::string first = extract_string(stream);
std::string second = extract_string(stream);
std::string newname = first + " " + second + " " + timestamp(fname);
std::cout << (("rename \"" + fname + "\" \"" + newname + "\"").c_str());
}
}
You'd use it in exactly the same way. Of course, you could make this print the newname
instead, and use it from your own script(s). Edit Edited the version to cross compile to win-exe. Made it print a rename
command.