tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Shell Command Substitution and fork()



    Date:        Tue, 21 Jun 2016 23:27:41 +0200
    From:        Edgar =?iso-8859-1?B?RnXf?= <ef%math.uni-bonn.de@localhost>
    Message-ID:  <20160621212740.GL12818%trav.math.uni-bonn.de@localhost>

  | So it's probably hard to get right.

Non trivial yes, some of the things that can be done which have to be
undone are var assignments, option changes, redirections, and anything
that does a sys call that affects the shell environ (cd, ulimit, ...)

  | I would hope for 3. so one could plug that code (or concept) into ash.

Unfortunately the issues relate to the whole structure of the shell.  If
you want ksh93, you can just use it, copying its source code to src/bin/sh
and calling it the NetBSD shell wouldn't really achieve anything useful.

The "whole structure" includes the way the shell does memory management
(it deals with LOTS of temporary strings, etc) error handling, ...

  | Or a function.

Yes.

  | Whereas, with a function, one could circumvent the problem by making the 
  | function assign the result to a global variable instead of printing it.

Often, yes.

  | > But in some cases, depending upon exactly what the printf is doing,
  | > there can be other ways.
  | Yes, please?

The stuff that is doing base conversion (or appears to be here) isn't
going to be trivial (of course, one could write a function to do it using
basic arithmetic ( $(( )) ), but that's not going to be very quick most
likely)

  | The printf's are like
  | 	printf "%02X%02X:%02X%02X" "$@"
  | or
  | 	printf "%04X" 0x"$xyz"

I think those two are just the same thing right?  That is, print
a hex number (string) in a fixed width field with leading 0's, using
upper case A-F for the >=10 hex digits (whether the input is upper or lower)

To take just the second one (the first is just the same thing, more or
less, 4 times, and just 2 digits each, with a : stuck in the middle...)
assuming "$@" contains data that is already explicitly hex - if it is actually
doing base conversion (11 --> B) then it would need extra help.

There are two parts to that, one to convert lower case to upper ...

	while :
	do
		case "${xyz}" in
		*a*) xyz=${xyz%a*}A${xyz#*a} ;;
		*b*) xyz=${xyz%b*}B${xyz#*b} ;;
		# same for c d e f
		*)	break;;
		esac
	done

and then to make it (at least) 4 chars long with leading 0's as required

	case "${xyz}" in
	?)	xyz=000${xyz} ;;
	??)	xyz=00${xyz} ;;
	???)	xyz=0${xyz} ;;
	esac

whether that ends up being faster than a fork and printf I have no idea.

  | or
  | 	printf "%0$(( 33 - ${#xyz} ))X" 0

That's (I think) making a long string of 0's enough so that when $xyz
is appended it will be 33 chars long

	p=		# the result is in p
	while :
	do
		case $(( 33 - ${#p} - ${#xyz} )) in
		0)	break ;;
		1)	p=0$p; break;;
		2)	p=00$p; break;;
		3)	p=000$p; break;;
		4)	p=0000$p; break;;
		*)	p=00000$p;;
		esac
	done

Obviously you can add more cases to make the loop iterate less, in the
extreme you could enumerate all 33 cases and remove the loop completely
(in that case you also don't need ${#p} as that would simply be 0)

  | 	printf "%x" 0x"$(printf "%.4s" "${xyz}")"

That one is just extracting the first 4 chars of the string, 
converting hex to lower case, and omitting leading 0's.   I'l omit
the case conversion part (can be done as above, backwards)
what's left is ...

	x=${xyz}			# x is going to be the answer
	case "${x}" in
	?|??|???|????)	;;
	*)		y=${x#????}; x=${x%${y}};;
	esac
	x=${x##0}
	test -z "${x}" && x=0

  | or
  | 	printf "%.$(($2 / 4))s%s\n" "$1" "${3#$(printf "%.$(($2 / 4))s" "$3")}"

This is slightly trickier, as the length to be extracted from each string
is variable, but it can be done too ($2 is obviously a bit length, so $2/4
is the number of hex digits - except that it is broken for any but count that
isn't an even multiple of 4 ( for 17 you'd get 4 chars, whereas 5 are really
needed - with some bits forced 0).

Unless any of this was going to be in very heavily used code, I wouldn't
even think of any of this however, doing it the simple clear way almost
always wins - people time is generally far more important than a few
cpu cycles.

kre



Home | Main Index | Thread Index | Old Index