LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Blogs > Skaperen
User Name
Password

Notices


Rate this Entry

A different way to do I/O redirection

Posted 03-31-2021 at 07:57 PM by Skaperen
Updated 03-31-2021 at 08:02 PM by Skaperen

sometimes i encounter situations where i am putting a command in where i cannot use I/O redirection.

when i am providing a command as token words to a program or other command, using redirection may not work or be understood. the command may be read by the program or be provided in arguments on the command line that runs the program. for example it could be running the provided command somewhere else like a different directory, different user, or different host. maybe the redirection needs to be done remotely. if you can run a one-time command string in that shell, such as the -c option for /bin/sh you might be able to quote the entire command.

not all situations can do that. perhaps quoting cannot be used. perhaps the command will get parsed and apply the redirection in the wrong place.

i have created a workaround for this. a single shell script that changes its behavior based on the command name used to run it. it has 3 primary commands it can do, "i", "o", and "e". used with a single letter name, it takes on file name followed by one command. it will redirect one standard I/O descriptor according to which letter is used then run the given command. for example:
Code:
i inputfile  command its arguments
o outputfile  othercommand its arguments
e erroroutputfile  somecommand its arguments
if you want to do more than one redirection, you could cascade the commands:
Code:
i inputfile o outputfile e erroroutputfile  command its arguments
the script can handle 2 or 3 letters in its name to handle multiple redirection. the file names are used in the order of the letters:
Code:
oi outputfile inputfile  command its arguments
ioe inputfile outputfile erroroutputfile  command its arguments
it's one script in Python3. you can make symlinks for all the other names you want to use. here is the script:

eio.py:
Code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""eio (or its custom aliases):

Copyright © 2021, by Phil D. Howard - all other rights reserved

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

The author may be contacted by decoding the number
11054987560151472272755686915985840251291393453694611309
(provu igi la numeron al duuma)

with command name, 1-3 file names, then command to run and its args,
it redirects 1-3 files to stdin/stdout/stderr of the command to run.
the order of the letters is the order of the file name arguments.
any alias can be used that has 1-3 of these letters: eio

letters eioa in command name imply files or mode:
e - open next named file to write stderr
i - open next named file to read stdin
o - open next named file to write stdout
a - use append mode for stdout and/or stderr

invalid alias names may have goofy results or worse.
the same letter more than once is ambiguous/invalid.
you can omit the command to run and it runs /bin/cat.
intended for POSIX systems (uses file descriptors).
tested on Ubuntu Linux.
"""

from sys import argv as v
import os

fds = dict( # map eio letter to fd
    i = 0,
    o = 1,
    e = 2,
)

flags = ( # map fd to flags
    os.O_RDONLY,
    os.O_WRONLY|os.O_CREAT|os.O_TRUNC,
    os.O_WRONLY|os.O_CREAT|os.O_TRUNC,
)

cmd = v.pop(0).rsplit('/',1)[-1].rsplit('.',1)[0].lower()
fns = [None]*3
s = set()
for l in cmd:
    if l in s:
        exit(f'letter {l!r} repeats in command name')
    if l=='a':
        flags[1] |= os.O_APPEND
        flags[2] |= os.O_APPEND
    if l in fds:
        if not v:
            exit(f'file name missing for {l!r}')
        fns[fds[l]] = v.pop(0)
        s.add(l)

if not v:
    v = ['/bin/cat']

n = len(s)
if n>1 and not v:
    exit(f'command missing after {n} file names')

er = 0
for fd in (0,1,2):
    fn = fns[fd]
    if fn:
        if not fn:
            continue
        if fn=='-':
            continue
        try:
            nd = os.open(fn,flags[fd])
        except Exception:
            nd = -9
        if nd<0:
            print(f'error {nd} opening file {fn!r}, command {v[0]!r} not run')
            er += 1
        else:
            os.dup2(nd,fd)

if er:
    exit(f'aborting due to {er} error{"s"[er==1:]}')

if not v:
    v = ['/bin/cat']
os.execvp(v[0],v)
Posted in Uncategorized
Views 661 Comments 0
« Prev     Main     Next »
Total Comments 0

Comments

 

  



All times are GMT -5. The time now is 04:01 PM.

Main Menu
Advertisement
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration