Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have a system with restricted calculational power (fritzbox) and functions (busybox) and an webcam, able to deliver JPG files.
Now I'm looking for for a method (based on shell script) to download JPG files every 5 seconds, save them (that's no problem with wget) and stream them later through a webserver.

I set up everything but encountered some problem: As the system is getting very slow with so many JPG files in a folder (even if I split them up to several folders) I thought about writing them to a single file (echo, cat, ...) and extracting them later again (sed, awk).
Now, shell scripts are not really comfortable dealing with binary data, so "echo" and "cat" commands fail as they don't produce readable jpg-files.

I download the JPG file with wget either to a temporary file or to a variable. At the moment I then cat each new JPG to a common file, separated by a unique string e.g. "--myboundary", which I echo in without newlines.

How can I now extract the single jpg's from this common file which contains all the JPGs? I tried awk, but got somehow crap results.

share|improve this question
add comment

2 Answers 2

If you can start over, just use tar. It has an "append mode" with the r option:

$ ls t.tar
ls: cannot access t.tar: No such file or directory
$ tar rvf t.tar t.c
t.c
$ tar rvf t.tar t.cpp
t.cpp
$ tar tf t.tar
t.c
t.cpp

(As you can see, the tar file doesn't have to exist to use the append mode, so it should be really easy to use for your case.)

If you don't have the luxury of a full GNU tar implementation, awk should be able to sort your merged file out with something like (taken from this Stack Overflow post):

awk -vRS="--myboundary" '{ print $0 > NR".jpg" }' yourfile

This will create files called 1.jpg, 2.jpg, etc. Problem: it adds a stray \n at the end of the file.
Assuming you have truncate and stat in your environment, you can fix those files up with:

truncate -s $(( $(stat -c %s 1.jpg) - 1 )) 1.jpg

If you don't have stat, you'll need something else to figure out the filename (parsing the output of ls might be ok in this circumstance since you know the filenames are sane). If you don't have truncate, you can do the trick with dd, or possibly with head or tail.
Or you can ignore the trailing \n, chances are good the images will display correctly regardless.

Demo:

$ cp orig.1.png blob
$ echo -n "HELLOHELLO" >> blob 
$ cat orig.2.png >> blob 
$ ls -l
total 36
-rw-r--r-- 1 test test 14916 Dec 30 19:42 blob
-rw-r--r-- 1 test test  5735 Dec 30 19:41 orig.1.png
-rw-r--r-- 1 test test  9171 Dec 30 19:41 orig.2.png

$ awk -vRS="HELLOHELLO" '{print $0 > "new."NR".png"}' blob
$ ls -l
total 56
-rw-r--r-- 1 test test 14916 Dec 30 19:42 blob
-rw-r--r-- 1 test test  5736 Dec 30 19:43 new.1.png
-rw-r--r-- 1 test test  9172 Dec 30 19:43 new.2.png
-rw-r--r-- 1 test test  5735 Dec 30 19:41 orig.1.png
-rw-r--r-- 1 test test  9171 Dec 30 19:41 orig.2.png

$ for i in new* ; do truncate -s $(( $(stat -c %s $i) - 1 )) $i ; done
$ ls -l
total 56
-rw-r--r-- 1 test test 14916 Dec 30 19:42 blob
-rw-r--r-- 1 test test  5735 Dec 30 19:43 new.1.png
-rw-r--r-- 1 test test  9171 Dec 30 19:43 new.2.png
-rw-r--r-- 1 test test  5735 Dec 30 19:41 orig.1.png
-rw-r--r-- 1 test test  9171 Dec 30 19:41 orig.2.png
$ md5sum *.png
70718d7b9e717206b4a8455ea32b51ed  new.1.png
531099b9527f5fc2b623a3f724573ea9  new.2.png
70718d7b9e717206b4a8455ea32b51ed  orig.1.png
531099b9527f5fc2b623a3f724573ea9  orig.2.png
share|improve this answer
    
Thanks for the fast answer Mat. Unfortunately the busybox version of tar does not support the "-r" option. It is an interesting idea to use an archive directly. Do you know any method of how to extract the different jpg's from one concatenated file as mentioned in the question? –  user13816 Dec 30 '11 at 18:07
    
Could you try the awk variation I just edited in? –  Mat Dec 30 '11 at 18:29
    
I tryed it, thanks. It seems to work. The pictures can be viewed(eye of gnome). Don't you think I can circumvent the problem with the trailing /n by setting ORS=""? –  user13816 Dec 30 '11 at 19:31
    
ok, thanks a lot Mat. That did the trick. The ORS="" also removes the newline, so the extracted images are identical to the original ones. –  user13816 Dec 30 '11 at 22:24
add comment

You are pretty much trying to reinvent tar or similar archiving formats; don't expect doing things manually to be easier than using existing tools.

If you insist on a custom boundary (which is dangerous, as this boundary could appear naturally in one of the jpeg files), make it start and end with a newline. This will facilitate processing with awk.

I recommend keeping every file separate, but limiting the number of files per directory to a small enough number that doesn't cause a performance hit. With one file every 5 seconds, a nesting structure of day/hour/minute gives a maximum branching of 366/60/20 which should be ok performance-wise.

If you want to use archives, and given the lack of an r command in Busybox tar, you could store N files in the filesystem, then periodically make an archive with the existing files and clean the slate. For example, to make an archive every 100 files:

set -- *
if [ $# -gt 100 ]; then
  set ../archives/*.tar
  eval "last=\${$#}"
  last=${last%[!0-9]}; last=${last##[!0-9]}
  tar cf ../archives/$((last+1)).tar -- *
  rm -- *
fi
share|improve this answer
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.