outputting a command to the terminal?

J

John Salerno

Here's my new project: I want to write a little script that I can type
at the terminal like this:

$ scriptname package1 [package2, ...]

where scriptname is my module name and any subsequent arguments are the
names of Linux packages to install. Running the script as above will
create this line:

sudo aptitude install package1 package2 ...

It will run that line at the terminal so the package(s) will be installed.

Now, the extra functionality I want to add (otherwise I would just
install them normally!) is to save the package names to a text file so I
can now the names of programs I've manually installed, if I ever want to
check the list or remove packages.

So creating the proper bash command (sudo aptitude install ...) is easy,
and writing the names to a file is easy. But I have two questions:

1. First of all, does Linux keep track of the packages you manually
install? If so, then I won't have to do this at all.

2. Assuming I write this, how do output the bash command to the
terminal? Is there a particular module that Python uses to interact with
the terminal window that I can use to send the install command to the
terminal?

Thanks.
 
D

Diez B. Roggisch

John said:
Here's my new project: I want to write a little script that I can type
at the terminal like this:

$ scriptname package1 [package2, ...]

where scriptname is my module name and any subsequent arguments are the
names of Linux packages to install. Running the script as above will
create this line:

sudo aptitude install package1 package2 ...

It will run that line at the terminal so the package(s) will be installed.

Now, the extra functionality I want to add (otherwise I would just
install them normally!) is to save the package names to a text file so I
can now the names of programs I've manually installed, if I ever want to
check the list or remove packages.

So creating the proper bash command (sudo aptitude install ...) is easy,
and writing the names to a file is easy. But I have two questions:

1. First of all, does Linux keep track of the packages you manually
install? If so, then I won't have to do this at all.

2. Assuming I write this, how do output the bash command to the
terminal? Is there a particular module that Python uses to interact with
the terminal window that I can use to send the install command to the
terminal?


You don't put a command to the terminal. The shell executes commands.
But it is mainly just a program itself - it can spawn subprocesses and
make these execute the actual commands. so - the module you need is most
probably subprocess.

Diez
 
Y

Yu-Xi Lim

John said:
1. First of all, does Linux keep track of the packages you manually
install? If so, then I won't have to do this at all.

I assume you're using a Debian-based distro with aptitude as the front
end. In which case, all dpkg operations should be logged in
/var/log/dpkg.log

Generally, after the initial installation, all subsequent operations are
either updates of existing packages or packages you installed manually.
Only rarely do you get new packages installed automatically as a result
of an additional dependency from an original automatically installed
package.

If you know when you completed your initial installation, you can easily
parse the log files to determine what else was installed after that.
2. Assuming I write this, how do output the bash command to the
terminal? Is there a particular module that Python uses to interact with
the terminal window that I can use to send the install command to the
terminal?

I'm wondering about the need to "output the bash command to the
terminal". It would probably suffice if your Python script just spawned
an instance of the shell with the necessary command line. Take a look at
the subprocess module.

But this really calls for a bash script:

#!/bin/bash
echo $@ >> /path/to/manual_install.log
sudo aptitude install $@


Shorter than the equivalent Python code. You could probably declare this
as a function in your bash initialization files too, if you know how to
do this.
 
J

John Salerno

Yu-Xi Lim said:
I assume you're using a Debian-based distro with aptitude as the front
end. In which case, all dpkg operations should be logged in
/var/log/dpkg.log

Yes, I'm using Ubuntu. But I checked this log file and I'm a bit
confused. It has a lot of listings for 5-31-06, but I didn't even
install Linux until last Saturday. The next date after 5-31 is 8-5-06,
and I know I installed things between last Saturday and Aug. 5.

(But this is OT, so don't worry about it.)
I'm wondering about the need to "output the bash command to the
terminal". It would probably suffice if your Python script just spawned
an instance of the shell with the necessary command line. Take a look at
the subprocess module.

But this really calls for a bash script:

#!/bin/bash
echo $@ >> /path/to/manual_install.log
sudo aptitude install $@


Shorter than the equivalent Python code. You could probably declare this
as a function in your bash initialization files too, if you know how to
do this.

Hmm, interesting. I figured I could do this with a bash script, but I
don't know bash at all and I'm trying to stick with Python. I don't
quite understand your bash script (not familiar with the $@ syntax).

I think I'll take a look at the subprocess module, just for fun. :)
 
J

John Machin

John said:
I think I'll take a look at the subprocess module, just for fun. :)

.... and for learning too :)

Also, consider that some operating system commands are built into the
shell (i.e. not run as a separate process), which makes using the
subprocess module a bit difficult -- for more fun and learning, check
out os.system()

Cheers,
John
 
D

Dennis Lee Bieber

Yes, I'm using Ubuntu. But I checked this log file and I'm a bit
confused. It has a lot of listings for 5-31-06, but I didn't even
install Linux until last Saturday. The next date after 5-31 is 8-5-06,
and I know I installed things between last Saturday and Aug. 5.
Pardon, between when?

August 5 was "last Saturday" if you ignore "yesterday" (well, since
my watch says it is now Monday... "day before last").

I'd guess the "May 31" entries are those that were "snapshots" of
the OS installer date. August 5, first Saturday in the month, might be
the first non-standard installed package.
Hmm, interesting. I figured I could do this with a bash script, but I
don't know bash at all and I'm trying to stick with Python. I don't
quite understand your bash script (not familiar with the $@ syntax).
Well, I don't do shell scripts either, but... looking at the
sample... "$@" is likely the shell equivalent of Python's sys.argv -- or
*sys.argv if passed down
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
J

John Salerno

Dennis said:
Pardon, between when?

Wow, I can't believe how time goes. Aug. 5 *was* the first day! I knew I
had installed it a week ago, but I was thinking it was the last Saturday
in July, not Aug. 5 already!
 
S

Steven Bethard

John said:
Here's my new project: I want to write a little script that I can type
at the terminal like this:

$ scriptname package1 [package2, ...]

where scriptname is my module name and any subsequent arguments are the
names of Linux packages to install. Running the script as above will
create this line:

sudo aptitude install package1 package2 ...

It will run that line at the terminal so the package(s) will be installed.

Now, the extra functionality I want to add (otherwise I would just
install them normally!) is to save the package names to a text file so I
can now the names of programs I've manually installed, if I ever want to
check the list or remove packages.

So creating the proper bash command (sudo aptitude install ...) is easy,
and writing the names to a file is easy. But I have two questions:

1. First of all, does Linux keep track of the packages you manually
install? If so, then I won't have to do this at all.

2. Assuming I write this, how do output the bash command to the
terminal? Is there a particular module that Python uses to interact with
the terminal window that I can use to send the install command to the
terminal?


I don't know the answer to the first bit here, but I think the following
should get you most of what you want as far as the second bit is concerned:


---------------------------- scriptname.py ----------------------------
import argparse # http://argparse.python-hosting.com/
import subprocess
import sys

def outputfile(filename):
return open(filename, 'w')

if __name__ == '__main__':
# parse the command line arguments
parser = argparse.ArgumentParser()
parser.add_argument('packages', metavar='package', nargs='+',
help='one of the packages to install')
parser.add_argument('--save', type=outputfile, default=sys.stdout,
help='a file to save the package names to')
namespace = parser.parse_args()

# call the command
command = ['sudo', 'aptitude', 'install'] + namespace.packages
subprocess.call(command)

# write the package name file
for package_name in namespace.packages:
namespace.save.write('%s\n' % package_name)
-----------------------------------------------------------------------


$ scriptname.py -h
usage: scriptname.py [-h] [--save SAVE] package [package ...]

positional arguments:
package one of the packages to install

optional arguments:
-h, --help show this help message and exit
--save SAVE a file to save the package names to



STeVe
 
J

John Salerno

Steven said:
John said:
Here's my new project: I want to write a little script that I can type
at the terminal like this:

$ scriptname package1 [package2, ...]

where scriptname is my module name and any subsequent arguments are
the names of Linux packages to install. Running the script as above
will create this line:

sudo aptitude install package1 package2 ...

It will run that line at the terminal so the package(s) will be
installed.

Now, the extra functionality I want to add (otherwise I would just
install them normally!) is to save the package names to a text file so
I can now the names of programs I've manually installed, if I ever
want to check the list or remove packages.

So creating the proper bash command (sudo aptitude install ...) is
easy, and writing the names to a file is easy. But I have two questions:

1. First of all, does Linux keep track of the packages you manually
install? If so, then I won't have to do this at all.

2. Assuming I write this, how do output the bash command to the
terminal? Is there a particular module that Python uses to interact
with the terminal window that I can use to send the install command to
the terminal?


I don't know the answer to the first bit here, but I think the following
should get you most of what you want as far as the second bit is concerned:


---------------------------- scriptname.py ----------------------------
import argparse # http://argparse.python-hosting.com/
import subprocess
import sys

def outputfile(filename):
return open(filename, 'w')

if __name__ == '__main__':
# parse the command line arguments
parser = argparse.ArgumentParser()
parser.add_argument('packages', metavar='package', nargs='+',
help='one of the packages to install')
parser.add_argument('--save', type=outputfile, default=sys.stdout,
help='a file to save the package names to')
namespace = parser.parse_args()

# call the command
command = ['sudo', 'aptitude', 'install'] + namespace.packages
subprocess.call(command)

# write the package name file
for package_name in namespace.packages:
namespace.save.write('%s\n' % package_name)
-----------------------------------------------------------------------


$ scriptname.py -h
usage: scriptname.py [-h] [--save SAVE] package [package ...]

positional arguments:
package one of the packages to install

optional arguments:
-h, --help show this help message and exit
--save SAVE a file to save the package names to



STeVe

yikes! I'll have to take some time to study this! I appreciate it. :)
 
Y

Yu-Xi Lim

Dennis said:
Well, I don't do shell scripts either, but... looking at the
sample... "$@" is likely the shell equivalent of Python's sys.argv -- or
*sys.argv if passed down

Yeah, kinda equivalent to *sys.argv[1:].
 
S

Steven Bethard

John said:
Steven said:
---------------------------- scriptname.py ----------------------------
import argparse # http://argparse.python-hosting.com/
import subprocess
import sys

def outputfile(filename):
return open(filename, 'w')

if __name__ == '__main__':
# parse the command line arguments
parser = argparse.ArgumentParser()
parser.add_argument('packages', metavar='package', nargs='+',
help='one of the packages to install')
parser.add_argument('--save', type=outputfile, default=sys.stdout,
help='a file to save the package names to')
namespace = parser.parse_args()

# call the command
command = ['sudo', 'aptitude', 'install'] + namespace.packages
subprocess.call(command)

# write the package name file
for package_name in namespace.packages:
namespace.save.write('%s\n' % package_name)
-----------------------------------------------------------------------


$ scriptname.py -h
usage: scriptname.py [-h] [--save SAVE] package [package ...]

positional arguments:
package one of the packages to install

optional arguments:
-h, --help show this help message and exit
--save SAVE a file to save the package names to


yikes! I'll have to take some time to study this! I appreciate it. :)


For just calling the command, the important lines are::

command = ['sudo', 'aptitude', 'install'] + namespace.packages
subprocess.call(command)

where you could have probably used ``sys.argv[1:]`` instead of
namespace.packages.


For writing the file, as I'm sure you've already figured out, the
important lines are::

for package_name in namespace.packages:
namespace.save.write('%s\n' % package_name)

where again, if you weren't using argparse, you could have used
``sys.argv`` to determine the package names (namespace.packages) and the
file to write to (namespace.save).


The remaining lines involving the ``parser`` object are basically
defining a command line interface in a similar way to what optparse in
the stdlib does. Sure, you could do all of this by fiddling with
sys.argv, but the argparse module will do all the parsing and
conversions for you, and give your script a meaningful usage message.
And I'm a firm believer in meaningful usage messages. =)

STeVe

P.S. Thank *you* for posting this. As a result, I've been convinced
that argparse should grow a 'outfile' type, something I've been debating
with myself about for a while now.
 
J

John Salerno

Steven said:
P.S. Thank *you* for posting this. As a result, I've been convinced
that argparse should grow a 'outfile' type, something I've been debating
with myself about for a while now.

Heh heh. I'm glad my ignorance can inspire those around me. ;)
 
S

Steven Bethard

Yu-Xi Lim said:
Why not the standard lib's optparse?

The page referenced above gives a variety of reasons, but the two most
important things in this example are: argparse supports parsing of both
positional and optional arguments, and argparse generates better usage
messages.

Since argparse supports positional arguments, I can write something like::

parser.add_argument('packages', ..., nargs='+', ...)

and then the arparse module will enforce that at least one positional
argument was given. With optparse, you'd do something like:

options, args = parser.parse_args()
if not args:
parser.error('wrong number of arguments')

Basically, with optparse, anything that involves positional arguments
has to be handled by the user.

It's also worth pointing out the better usage messages. Notice that the
output looked like::

$ scriptname.py -h
usage: scriptname.py [-h] [--save SAVE] package [package ...]

positional arguments:
package one of the packages to install

optional arguments:
-h, --help show this help message and exit
--save SAVE a file to save the package names to

With the optparse, you'd get something like::

$ scriptname.py -h
usage: scriptname.py [OPTIONS]

options:
-h, --help show this help message and exit
--save SAVE a file to save the package names to

The argparse module knows how to create a meaningful usage message
instead of just "%prog [OPTIONS]", and the argparse module knows about
positional arguments, so you can have help messages for them too.

Ok, enough propaganda for now. ;-)

STeVe
 
S

Simon Forman

John said:
Yes, I'm using Ubuntu. But I checked this log file and I'm a bit
confused. It has a lot of listings for 5-31-06, but I didn't even
install Linux until last Saturday. The next date after 5-31 is 8-5-06,
and I know I installed things between last Saturday and Aug. 5.

(But this is OT, so don't worry about it.)


Hmm, interesting. I figured I could do this with a bash script, but I
don't know bash at all and I'm trying to stick with Python. I don't
quite understand your bash script (not familiar with the $@ syntax).

I think I'll take a look at the subprocess module, just for fun. :)

Hey John, Yu-Xi Lim's right. This is one of those (thankfully few)
cases where bash makes more sense to use than python (at least IMHO.)

To figure out about that $@, fire up your teminal and type "man bash"
("!man bash" in IPython) (BTW, apropos of nothing, "man bash" is one of
my all time favorite commands ever. I always think of some comic-book
hero/monster shouting it, "MAN BASH!!" lol. Anyway...)

So, now you're looking at the man page for bash. It's very very long
and ubergeeky. Deep and amazing mysteries are contained (and kind of
explained) within it. You want information on $@ so we'll use the
search incantation to find and reveal it.

Type "/\$@" without the quotes, then press return. (What this
means/does: "/" is the manpage search command, it uses a regular
expression syntax not dissimilar to python's own. "\" escapes the next
character ("$", in this case) and we need to do that because "$" is
regular expression syntax for "end of line". The "$@" will now match,
um, "$@" correctly.)

Once you press return, man will scroll to put the first occurance of
"$@" at the top of your terminal and highlight it. On my system it's
this line (I narrowed my terminal so that quoted portions wouldn't wrap
badly in this posting):

"$@" as explained below under Special Parameters.

So far so good, '"$@" as explained below' looks promising. Rather than
scrolling down to find this "Special Parameters" section, let's keep
using the search.

Press "n" to scroll to the next occurance of our pattern "$@". On my
system this brings me to:

separate word. That is, "$@" is equivalent to
"$1" "$2" ... If the double-quoted expansion

Ah ha! Scrolling up a few lines, we see:

@ Expands to the positional parameters, starting
from one. When the expansion occurs within
double quotes, each parameter expands to a
separate word. That is, "$@" is equivalent to
"$1" "$2" ... If the double-quoted expansion
occurs within a word, the expansion of the
first parameter is joined with the beginning
part of the original word, and the expansion
of the last parameter is joined with the last
part of the original word. When there are no
positional parameters, "$@" and $@ expand to
nothing (i.e., they are removed).

Not extraordinarily enlightening, maybe, but better than sitting in the
dark, lighting your farts. :-D (Hit "q" to exit man.)

Basically what this means is that $@ will become the positional
arguments that you pass to your script. You can play with this by
writing a simple bash script like this

#!/bin/bash
echo $@

and passing it args to see what it echos. (Remember to chmod +x it..)

So, long story short, Yu-Xi Lim's bash script echos your package names
to the /path/to/manual_install.log file (">>" in bash means "append the
output of the command to the left to the file on the right",) then it
calls aptitude with those same package names.

It's simple, short, and to-the-point. The equivalent python script
would be much longer, for no appreciable gain. I write most of my tiny
little helper scripts in python, but in this case, bash is the clear
winnar. (And on *nix. man pages are your best friend. Plus you get to
feel all l33t when you grok them. lol)

Peace,
~Simon
 
J

John Salerno

Simon said:
It's simple, short, and to-the-point. The equivalent python script
would be much longer, for no appreciable gain. I write most of my tiny
little helper scripts in python, but in this case, bash is the clear
winnar. (And on *nix. man pages are your best friend. Plus you get to
feel all l33t when you grok them. lol)

Thanks for the info! I might grudgingly decide to use a bash script in
this case. :)

And yes, it seems every time I ask a Linux question, everyone points me
to a man page. Sometimes I find them difficult to decipher, but they are
still a great help.
 
S

Simon Forman

John said:
Thanks for the info! I might grudgingly decide to use a bash script in
this case. :)

You're welcome. lol :)
And yes, it seems every time I ask a Linux question, everyone points me
to a man page. Sometimes I find them difficult to decipher, but they are
still a great help.

Yup. When I started with Linux, man pages were one of those things I
resisted... until I started actually reading them. Then I kicked
myself for not starting sooner. :)

Neat trick: man -k <search term>
Shows you man pages matching your search term (I think it's the same
thing as the "apropos" command.) It searches the command names and
summary lines.

Peace,
~Simon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top