(patch for Bash) Python command substitution in Bash

William Park opengeometry at yahoo.ca
Fri Feb 14 18:53:18 EST 2003


To Bash/Python programmers,

Here is my patch to "command substitution" syntax of Bash to interface
with Python automatically.  Not quite "embedding", but close enough for
short one-liners.

If command string begins with '!', then the rest of string is sent to
Python as command-line argument with double quotes, ie.
    python -c "string"
This shortcut is intended for one-liners like
    b=$(!print (1+1j) + (2+3j) )
    echo $(! print 'a' + '$b' )
    echo $(! print [1,2] + ['q','w'] )
    pi=$(!
    import math
    print math.pi
    )
To improve readability, whitespaces after '!' are removed before sending
it to Python.  Also, you have to turn off history substitution (set +H)
to use the '!' character interactively.

Since the commands are within double-quote, the usual shell expansions
are done, enabling you to use shell variables.  For bigger jobs,
however, you should do something like
    exec 9<<EOF		(or "EOF")
    ...
    ...
    EOF
    python /dev/fd/9 ...
    exec 9<&-

-- 
William Park, Open Geometry Consulting, <opengeometry at yahoo.ca>
Linux solution for data management and processing. 



--- bash-2.05b/subst.c	Mon Jun 24 07:59:45 2002
+++ bash/subst.c	Fri Feb 14 18:34:09 2003
@@ -3842,8 +3842,46 @@
 	exit (EXECUTION_FAILURE);
       else if (function_value)
 	exit (return_catch_value);
-      else
-	exit (parse_and_execute (string, "command substitution", SEVAL_NOHIST));
+      else if (string[0] == '!') {
+	  /* If command string begins with '!', then the rest of string is sent
+	   * to Python as command-line argument with double quotes, ie.
+	   *	python -c "string"
+	   * This shortcut to Python is intended for one-liners like
+	   *	b=$(!print (1+1j) + (2+3j) )
+	   *	echo $(! print 'a' + '$b' )
+	   *	echo $(! print [1,2] + ['q','w'] )
+	   *	pi=$(!
+	   *	import math
+	   *	print math.pi
+	   *	)
+	   * To improve readability, whitespaces after '!' are removed before
+	   * sending it to Python.  Also, you have to turn off history
+	   * substitution (set +H) to use the '!' character interactively.
+	   *
+	   * Since the commands are within double-quote, the usual shell
+	   * expansions are done, enabling you to use shell variables.  For
+	   * bigger jobs, however, you should do something like
+	   *	exec 9<<EOF		(or "EOF")
+	   *	...
+	   *	...
+	   *	EOF
+	   *	python /dev/fd/9 ...
+	   *	exec 9<&-
+	   *
+	   * --William Park <opengeometry at yahoo.ca>
+	   */
+	  char *t, *newstring;
+	
+	  /* skip whitespaces after after '!' */
+	  for (t = string + 1; (*t) && spctabnl (*t) && isifs (*t); t++)
+	      ;
+	  newstring = (char *)xmalloc (strlen (string) + strlen ("python -c \"\"") + 1);
+	  sprintf (newstring, "python -c \"%s\"", t);
+
+	  /* newstring is free'd by parse_and_execute() */
+	  exit (parse_and_execute (newstring, "python command substitution", SEVAL_NOHIST));
+      } else			/* original code */
+	  exit (parse_and_execute (string, "command substitution", SEVAL_NOHIST));
     }
   else
     {
@@ -4360,7 +4398,7 @@
 #if defined (ARRAY_VARS)
     case VT_ARRAYVAR:
       a = (ARRAY *)value;
-      len = array_num_elements (a) + 1;
+      len = array_num_elements (a);	/* + 1;  --William Park <opengeometry at yahoo.ca> */
       break;
 #endif
     }




More information about the Python-list mailing list