Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Linux commands from Fortran

311 views
Skip to first unread message

Dieter Britz

unread,
Aug 13, 2012, 11:43:57 AM8/13/12
to
I want to write a program that controls the Linux command "mogrify"
in a search loop so that I get photos reduced to a certain size for a
home page. As it is, whether I use % reduction of specify the size in
pixels, the final size in Mb varies quite a bit, apparently at random,
from one photo to the next.

A program that calls the command, then the directory command into a
pipe, and reads the size, in a loop, would make sure that I get the
size I want.

I know (at least I believe) that invoking system commands is not
standard Fortran but can it be done? I work under Suse Linux 12.1
and have Intel Fortran 90/95 installed. The Fortran part would be easy,
it's only the system commands that I don't know how to do.

--
Dieter Britz

Steve Lionel

unread,
Aug 13, 2012, 12:06:39 PM8/13/12
to
On 8/13/2012 11:43 AM, Dieter Britz wrote:

> I know (at least I believe) that invoking system commands is not
> standard Fortran but can it be done? I work under Suse Linux 12.1
> and have Intel Fortran 90/95 installed. The Fortran part would be easy,
> it's only the system commands that I don't know how to do.

Intel Fortran has three library routines that can do this - there are
minor differences among them, so look at the documentation to see which
is most appropriate for you: SYSTEM, SYSTEMQQ, RUNQQ. For best results,
add USE IFPORT to the procedure calling these.

Fortran 2008 defines an intrinsic EXECUTE_COMMAND_LINE. Intel Fortran
does not yet support this.

--
Steve Lionel
Developer Products Division
Intel Corporation
Merrimack, NH

For email address, replace "invalid" with "com"

User communities for Intel Software Development Products
http://software.intel.com/en-us/forums/
Intel Software Development Products Support
http://software.intel.com/sites/support/
My Fortran blog
http://www.intel.com/software/drfortran

Refer to http://software.intel.com/en-us/articles/optimization-notice
for more information regarding performance and optimization choices in
Intel software products.

glen herrmannsfeldt

unread,
Aug 13, 2012, 2:49:02 PM8/13/12
to
Dieter Britz <dieterh...@gmail.com> wrote:

> I want to write a program that controls the Linux command "mogrify"
> in a search loop so that I get photos reduced to a certain size for a
> home page. As it is, whether I use % reduction of specify the size in
> pixels, the final size in Mb varies quite a bit, apparently at random,
> from one photo to the next.

The size of JPEG files can vary a lot, depending on the detail
needed to represent it, and, usually, on a parameter telling
how hard it should (lossy) compress.

> A program that calls the command, then the directory command into a
> pipe, and reads the size, in a loop, would make sure that I get the
> size I want.

Executing the command is usually not so hard. Reading a pipe
from Fortran, though, isn't so easy. On some, you can use
INQUIRE to get a file size, though. You could also redirect
directory listing output to a file, and then read the file.

> I know (at least I believe) that invoking system commands is not
> standard Fortran but can it be done? I work under Suse Linux 12.1
> and have Intel Fortran 90/95 installed. The Fortran part would be easy,
> it's only the system commands that I don't know how to do.

Most linux systems supply the C popen() and pclose() functions.
I believe that they are not supposed to be supported by C
interoperability, but you might be able to use them. It would,
though, be easier to do in C if that was the goal.

-- glen

A. M.

unread,
Aug 14, 2012, 5:45:50 PM8/14/12
to
All Linux Fortran compilers (as back as g77) support the Fortran System
Calls that used to be known as 3f from the appendix in the Unix manual.
G95 and gfortran give access to them in the form of intrinsic, while
Intel requires the USE of ifport module (that provides the interface).

If what you want to use is not provided as intrinsic (or by the module)
you could write either a C wrap (requires essentially only an
underscore ) or use the iso binding to C provided by the newer Fortran
standards.

Terence

unread,
Aug 14, 2012, 6:33:32 PM8/14/12
to
Essentially, you can do anything in the dynamic area by having one program
construct command code of the executing O/S, to be executed as a 'daughter
program' (if this is the easiest way to solve the problem), or else produce
some form of output to control a second program to executed the task. After
whch the parent program is handed back control to decide what to do next.

I have a long-time habit of writing most general-purpose programs, so that
they generate and output decision tables, constucted from the user's input
instructions (spoken or typed) to be used by a second-level program that
accomplishes the needed task.

As I've noted before, this is how a CPU operates: it uses microcoded tables
to actually manipulate the current contents of registers in executing a
'machine code' instruction.



Joe Rosevear

unread,
Aug 18, 2012, 1:22:25 AM8/18/12
to
Dieter,

I'm guessing that the error is in your understanding. I tried it and
there was nothing approximate about it.

My picture that I tested it on came from Wikipedia:

http://en.wikipedia.org/wiki/File:Pickle.jpg

If you right click on the image and save it to your computer, then you
can try my test:

I used xv to see how big the image was

xv 799px-Pickle.jpg

Now right click on the image and xv will tell you that it is

799 x 275 pixels

Click "quit" to leave, xv, then use mogrify to reduce the size 50%

mogrify -resize 50% 799px-Pickle.jpg

Use xv again as we did above. The size is now

400 x 138 pixels

I would say that is perfect (799/2=400, 275/2=138) considering the
limitations:

integer number of total pixels
maintain aspect ratio
width and height (in pixels) are integers

Perhaps you had a misunderstanding? I hope this helps.

-Joe Rosevear

Joe Rosevear

unread,
Aug 18, 2012, 1:36:35 AM8/18/12
to
Dieter,

I read your post more carefully, and I see something. Perhaps *I*
misunderstood. It seems you are trying for a target size not in pixel
width and height, but in Mb. Yes?

Are your pictures compressed? Jpeg (and some other formats) is a
compressed format. You can choose your compression. In mogrify I
think it is called "-quality".

For a webpage isn't the size of the picture in pixels more important
than the number of Megabytes that comprise it?

I'm not getting it.

-Joe

Dieter Britz

unread,
Sep 3, 2012, 11:27:21 AM9/3/12
to
On Mon, 13 Aug 2012 12:06:39 -0400, Steve Lionel wrote:

> On 8/13/2012 11:43 AM, Dieter Britz wrote:
>
>> I know (at least I believe) that invoking system commands is not
>> standard Fortran but can it be done? I work under Suse Linux 12.1 and
>> have Intel Fortran 90/95 installed. The Fortran part would be easy,
>> it's only the system commands that I don't know how to do.
>
> Intel Fortran has three library routines that can do this - there are
> minor differences among them, so look at the documentation to see which
> is most appropriate for you: SYSTEM, SYSTEMQQ, RUNQQ. For best results,
> add USE IFPORT to the procedure calling these.
>
> Fortran 2008 defines an intrinsic EXECUTE_COMMAND_LINE. Intel Fortran
> does not yet support this.

I have now tried this, and struck some strange problems. Here is
the little program, which I will expand to do the job:

program MOG
use IFPORT
! implicit none
character(len=80) :: SYSTEMQQ
character(len=80) :: lsline, inputfile, command
integer :: size

print '(" File name?")'
read (*,'(a)') inputfile
command = "ls -s " // inputfile
print '(a)', "Command = " // command
lsline = SYSTEMQQ (command)
! liline = SYSTEMQQ (command)
print '(a)', lsline
! print '(a)', liline
end program MOG

I get the message

src/mog.f90(4): error #6401: The attributes of this name conflict with
those made accessible by a USE statement. [SYSTEMQQ]
character(len=80) :: SYSTEMQQ
-----------------------^
src/mog.f90(12): error #6054: A CHARACTER data type is required in this
context. [SYSTEMQQ]
lsline = SYSTEMQQ (command)
-----------^
compilation aborted for src/mog.f90 (code 1)

When I deactivate the declaration of SYSTEMQQ and activate the
commented lines using liline, it works, strangely enough. This
was an accident, me typing "liline" instead of the intended
"lsline"

So, how do I use this? I declare the output line lsline as
character(len=80), and I assume SYSTEMQQ must be type character
as well, but what length? The manual on SYSTEMQQ doesn't tell
me how I should declare it in the example.

In some versions of my attempts, I get a message like

sh: $'\001': command not found

(e.g. when I cpomment out the USE statement).
What does this mean? I run the thing with the shell script,

ifort src/mog.f90
./a.out << eoi
wornrope.jpg
eoi
#
rm a.out



--
Dieter Britz

Jan Gerrit Kootstra

unread,
Sep 3, 2012, 11:38:19 AM9/3/12
to
Op 03-09-12 17:27, Dieter Britz schreef:
Dieter,


A function should not be declared as a "variable".
That is where you go wrong.


Kind regards,


Jan Gerrit

dpb

unread,
Sep 3, 2012, 12:24:21 PM9/3/12
to
On 9/3/2012 10:27 AM, Dieter Britz wrote:
> On Mon, 13 Aug 2012 12:06:39 -0400, Steve Lionel wrote:
...

>> Intel Fortran has three library routines that can do this - there are
>> minor differences among them, so look at the documentation to see which
>> is most appropriate for you: SYSTEM, SYSTEMQQ, RUNQQ. For best results,
>> add USE IFPORT to the procedure calling these.
...

> I have now tried this, and struck some strange problems. Here is
> the little program, which I will expand to do the job:
>
> program MOG
> use IFPORT
> ! implicit none
> character(len=80) :: SYSTEMQQ
...

> So, how do I use this? I declare the output line lsline as
> character(len=80), and I assume SYSTEMQQ must be type character
> as well, but what length? The manual on SYSTEMQQ doesn't tell
> me how I should declare it in the example.
...

Well, that's not exactly true; from the CVF manual (which I presume
Intel follows pretty doggone closely :) ) --

> SYSTEMQQ
> Run-Time Function: Executes a system command by passing a command string to the operating system's command interpreter.
>
> Module: USE DFLIB
>
> Syntax
>
> result = SYSTEMQQ (commandline)
>
>
> commandline
> (Input) Character*(*). Command to be passed to the operating system.
> Results:
>
> The result is of type LOGICAL(4). The result is .TRUE. if successful; otherwise, .FALSE..

program MOG
use IFPORT
implicit none

! trash this; the USE takes care of the declarations needed for the
!function --character(len=80) :: SYSTEMQQ

character(len=80) :: inputfile, command
integer :: size
! add the following per the documentation--SYSTEMQQ returns a flag
logical :: result

print '(" File name?")'
read (*,'(a)') inputfile
command = "ls -s " // inputfile
print '(a)', "Command = " // command
result = SYSTEMQQ (command)
...

Now, unfortunately, SYSTEMQQ will _NOT_ return the results of the system
command passed to the shell; you'll have to use redirection of the
output to a file and parse the file or some other ruse.

I don't know what they distribute on Linux platform; on Windows there is
a set of modules that have pre-built interfaces to a large portion of
the system API. I'd suggest looking there and see about calling them
directly instead since your into system-dependent stuff anyway.

--



Richard Maine

unread,
Sep 3, 2012, 3:44:54 PM9/3/12
to
Jan Gerrit Kootstra <jan.g...@kootstra.org.uk> wrote:

> Op 03-09-12 17:27, Dieter Britz schreef:

> > src/mog.f90(4): error #6401: The attributes of this name conflict with
> > those made accessible by a USE statement. [SYSTEMQQ]
> > character(len=80) :: SYSTEMQQ

> A function should not be declared as a "variable".
> That is where you go wrong.

Well.... no.

First off, he did not declare it as a variable. In fact, there isn't an
explicit way to do any such thing as declare something to be a variable.
This is occasionally a source of confusions. The closest thing to
declaring something as a variable is declaring it to have attributes
that only a variable can have. There are several such attributes, but
this example did *NOT* illustrate any of those.

In particular, the declaration

character(len=80) :: SYSTEMQQ

does not declare systemqq to be a variable. It declares it to have type
character and a length type parameter of 80. That's all. There are
things other than variables that can have those properties. At least 2
off the top of my head, and I suppose I might have forgotten something
else. With no information other than just that line, it could still be a
parameter or a function.

It is possible that you aren't used to pre-f90 style function usage.
Before f90, not only was it allowed to declare the type of your
functions in any scope that used them, it was required unless you relied
on implicit typing. As of f90, some people (myself included) moved more
towards putting procedures in modules in most cases, and using interface
bodies in most of the rest, so I don't much use the pre-f90 style
function declarations any more, but they are still perfectly fine
(except for functions that require explicit interfaces for some reason).

In short, the function declaration that Dieter showed was a perfectly
fine function declaration; that was not where he went wrong. The
above-quoted error message tells a different story. While I haven't used
systemqq myself, I'd lay (very high) odds that it is declared in the
IFPORT module that Dieter used. Trying to redeclare something that is
declared in a module that you use is not legal and is much more the
direction to look for his problem.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain

Jan Gerrit Kootstra

unread,
Sep 3, 2012, 4:54:20 PM9/3/12
to
Op 03-09-12 21:44, Richard Maine schreef:
Richard,


I come from f77.

Whether or not it is in a module, I am use to declare the function's
type in the function declaration line, not in the variable/parameter block.

http://quangech.blogsite.org/setup/Compilers/vrfortran/X86/DF/INCLUDE/DFLIB.F90

suggests SYSTEMQQ to be a function of type logical*4

so this is where Dieter may have gone wrong. The redeclaration as you
refer to.

I never learned anything about the f90+ style of programming, I only us
module for it was shown to me by my PhD studies in CFD tutor but due to
work in a complete other field never had the time to learn at the in and
outs of f90 programming.


Kind regards,


Jan Gerrit

P.S. one learns every day.



Richard Maine

unread,
Sep 3, 2012, 5:22:59 PM9/3/12
to
Jan Gerrit Kootstra <jan.g...@kootstra.org.uk> wrote:

> I come from f77.
>
> Whether or not it is in a module, I am use to declare the function's
> type in the function declaration line, not in the variable/parameter block.

You have to do it in the function statement and *ALSO* in whatever scope
uses it. That was the only option (other than implicit typing) in f77.
The routine that uses it doesn't get to "see" the function statement.
That is the essense of separate compilation, which f77 was designed
around.

If you aren't familliar with this (though I find it a little hard to
imagine doing much f77 code without already having run into it),
I suggest trying the following f77 (except for the lower case - I just
can't bring myself to type in all caps) code.

program p
x = 1.0
write (*,*) f(x)
end
character*80 function f(x)
f = 'hello world.'
end

I just tried it in gfortran. I got an output of 0.0000000, followed
by a segmentation fault. Any guess why? (That's a rhetorical question; I
know why).

If I make the "obvious" addition, it prints the expected output and
terminates normally.

By the way, there is no such concept in the language as a
"variable/parameter block". There is the specification part (I think
that's the term, but no tim to check it at the moment), and then there
is the execution part. Almost all explicit specifications go into the
specification part. Yes, that includes dclarations of function types.

> suggests SYSTEMQQ to be a function of type logical*4

Ah. So that was another problem.

> so this is where Dieter may have gone wrong. The redeclaration as you
> refer to.

Still no. Declaring it *AT ALL* in his subroutine is a redeclaration,
and thus is illegal. Apparently he also got the type incorrect, but
that's a separate error. Even if he got the type correct, it is illegal
to declare it twice, which his code essentially did - once in the used
module and once in his source code.

It isn't exactly the same thing because of the module involvement, but
try adding the declaration

character*80 f

in th emain program of the above f77 code. And add it twice; yes
duplicate the line. Adding it once makes the code run correctly. Adding
it twice gives me the compilation error message

character*80 f
1
Error: Symbol 'f' at (1) already has basic type of CHARACTER

That's about as close as I can get in f77 to the same kind of error.
Note that there is nothing wrong with the declarations of f - just that
there are 2 of them.

dpb

unread,
Sep 3, 2012, 5:24:11 PM9/3/12
to
On 9/3/2012 3:54 PM, Jan Gerrit Kootstra wrote:
> Op 03-09-12 21:44, Richard Maine schreef:
...

>> In particular, the declaration
>>
>> character(len=80) :: SYSTEMQQ
>>
>> does not declare systemqq to be a variable. It declares it to have type
>> character and a length type parameter of 80. That's all. ...
>>
>> It is possible that you aren't used to pre-f90 style function usage.
>> Before f90, not only was it allowed to declare the type of your
>> functions in any scope that used them, it was required unless you relied
>> on implicit typing. As of f90, some people (myself included) moved more
>> towards putting procedures in modules in most cases, and using interface
>> bodies in most of the rest, so I don't much use the pre-f90 style
>> function declarations any more, but they are still perfectly fine
>> (except for functions that require explicit interfaces for some reason).
>>
>> In short, the function declaration that Dieter showed was a perfectly
>> fine function declaration; that was not where he went wrong. ...
...
> I come from f77.
>
> Whether or not it is in a module, I am use to declare the function's
> type in the function declaration line, not in the variable/parameter block.
...

That still only declares the type for the declaration of the function
itself--it would still be missing the declaration in the
calling/referencing procedure (or main program in this case). If the
function is not consistent with implicit typing (as also is true in this
case) then there will be a mismatch between the function as declared and
the calling routine's view of it (again, w/o modules or an explicit
interface otherwise supplied).

So, as Richard points out, F77 or no, declaring the function type
somewhere else other than in the definition line of the function is
still needed (and _especially_ in F77 as there is no other way).
>
> suggests SYSTEMQQ to be a function of type logical*4

Yes, see my other followup to OP...and it also doesn't do what OP was
hoping for it to do... :(

--

Dieter Britz

unread,
Sep 4, 2012, 3:25:29 AM9/4/12
to
You are no doubt right, but I want the picture to appear on
people's screen reasonably fast, and I decided that files of
about 400 kb are a good compromise between this and picture
quality. Hence my plan for this program.

But thanks for the advice.
--
Dieter Britz

Dieter Britz

unread,
Sep 4, 2012, 6:14:59 AM9/4/12
to
On Mon, 13 Aug 2012 15:43:57 +0000, Dieter Britz wrote:

> I want to write a program that controls the Linux command "mogrify"
> in a search loop so that I get photos reduced to a certain size for a
> home page. As it is, whether I use % reduction of specify the size in
> pixels, the final size in Mb varies quite a bit, apparently at random,
> from one photo to the next.
[...]

I now got this going, thanks to a few suggestions from this ng. The
program is now

program MOG
use IFPORT
implicit none
character(len=80) :: inputfile, command, line
logical :: com
integer :: L, size

print '(" File name?")'
read (*,'(a)') inputfile
L = LEN_TRIM (inputfile)
command = "ls -s " // inputfile(1:L) // " > pipe"
print '(a)', "Command = " // command
com = SYSTEMQQ (command)
print '(" Reading from the pipe:")'
OPEN (1, file="pipe", status="old")
read (1,'(a)') line
print '(a)', line
read (line,*) size
print '(" Size in blocks:", i6)', size
CLOSE (1)
command = "rm pipe"
com = SYSTEMQQ(command)

end program MOG

There is a file called pic.jpg, 34475 in size, and I get this
output:

File name?
Command = ls -s pic.jpg > pipe
Reading from the pipe:
36 pic.jpg
Size in blocks: 36

So now I can build this into the binary search for a file of
a wanted length. Interesting, a change form my normal Fortran
programming.

--
Dieter Britz
0 new messages