1

I bought a special digital camera that saves a proprietary image format, which ends in .lri. The company has a desktop program to render .lri files into standard jpg and dng files.

I'm finding that as I look at my directory where I've saved this files, I've missed converting some files. However my ability to visually notice missing pairs, the number of files, and the nested directory structure makes it difficult to definitely find all the files I want to convert.

I'm looking for a shell command to find files of extension .lri when there exists no matching filename of .dng (I'm not worried about jpg files presently). For instance, if I have L16_04198.lri, I should have L16_04198.dng, if I was diligent in my work months or years ago.

Edit Two constraints that I failed to mention: The files are in a nested directory structure, so this needs to be a recursive search. Also, I have spaces in the names of directories, so it needs to be able to handle that, also.

So I need a command or script that will report to me the filename L16_04198.lri, if it finds no L16_04198.dng, anywhere in the nested subdirectory structure (I may have rendered the file, but put it in the wrong subdirectory).

I'm familiar with the find command, but I'm not sure how to look for "not" a filename, and report if that name is not found.

1
1

tl;dr:

find . -name "*.txt" | perl -nle 's/\.txt$/.foo/; print unless -e' | cat -v

Here's an example using Perl

Note that we have a c.foo missing

$ ls
a.foo  a.txt  b.foo  b.txt  c.txt

We can find it this way

$ ls *.txt | perl -nle 's/\.txt$/.foo/; print unless -e '
c.foo

c.foo is missing


Update: dealing with filenames that contain metacharacters etc

Consider this set of filenames that contain spaces, newlines and pipe symbols

$ ls *txt
 a.txt   b.txt   c.txt  'd d.txt'  'e'$'\r''e.txt'  'f'$'\n''f.txt'  'g|g.txt'   taskmaster.txt

In practice Perl doesn't seem to have a problem parsing the output of ls:

$ ls *txt | perl -nle 's/\.txt$/.foo/; print unless -e'
c.foo
d d.foo
e.foo
f
f.foo
g|g.foo
taskmaster.foo

Obviously if your filenames contain control characters you may need to make them more visible

$ ls *txt | perl -nle 's/\.txt$/.foo/; print unless -e' | cat -v
c.foo
d d.foo
e^Me.foo
f
f.foo
g|g.foo
taskmaster.foo

If you want this to work recursively

$ find . -name "*.txt" | perl -nle 's/\.txt$/.foo/; print unless -e' | cat -v
./c.foo
./d d.foo
./e^Me.foo
./f
f.foo
./g|g.foo
./h*h.foo
./temp/j.foo
4
  • 1
    Parsing Ls has many pitfalls. What to use instead? – Quasímodo Jan 12 at 20:10
  • @Quasímodo: That is a good point but in practice I find it hard to create a filename that causes real problems in the processing of this specific command. Interpreting the output can be tricky but it is essentially correct I believe. – RedGrittyBrick Jan 12 at 22:18
  • Unfortunately this does not work recursively ls -r *.lri | perl -nle 's/\.lri$/.dng/; print unless -e ' ls: cannot access '*.lri': No such file or directory – user394 Jan 13 at 19:16
  • @user394: See update at end for recursive version – RedGrittyBrick Jan 14 at 15:19
3

You can try this:

shopt -s globstar
for f in **/*.lri; do 
  [[ ! $(find . -name "$(basename "${f%%.lri}").dng") ]] && realpath "$f"
done
2
  • If the file.dng is supposed to be in the same directory as the file.lri, then the loop body can be more simply [[ -f "${f%.lri}.dng" ]] || realpath "$f" – glenn jackman Jan 12 at 22:58
  • @Freddy right, done! – schrodigerscatcuriosity Jan 13 at 19:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.