Discussion:
comment on RFE: 'shift'' [N] ARRAYNAME
L A Walsh
2018-09-26 00:17:27 UTC
Permalink
It struck me as it might be convenient if 'shift' could take an optional
arrayname as an argument. Would that be possible or would it cause some
incompatibility?

i.e.
set one two three four five
shift ARGV
two three four five
shift 2 ARGV
four five

I know it can be done with a function, but with more mess.
I used (maybe there's a better way, but...):

(in my lib file ArFuncs.shh, that I can include)

[include stdalias]
#[include Types] #if type-checking include Types+line below
lshift () {
(($#)) || return 1
int nshift=1
if [[ $1 =~ ^[0-9]+$ ]]; then nshift=$1; shift;fi
#if ! isArr $1; then echo >&2 "Need arrayname"; return 1; fi
my ar=$1; shift
my h="$ar[@]"
set "${!h}"
shift $nshift
eval "${ar}=("$@")"
}; export -f lshift
Greg Wooledge
2018-09-27 12:35:51 UTC
Permalink
Post by L A Walsh
It struck me as it might be convenient if 'shift' could take an optional
arrayname as an argument. Would that be possible or would it cause some
incompatibility?
The biggest issue here is how you specify the arguments.

Shift already takes one optional argument: the number of items to shift
from the argv list. Adding a second optional argument leads to a quagmire.
Do you put the optional list name first, or do you put the optional number
first? If only one argument is given, is it a list name, or is it a number?

(OK, granted, in bash it is not permitted to create an array whose name
is strictly digits, but still.)

If you wish to write an array-shifting builtin, it would be better to give
it a new name. Don't blindly copy perl. It's not always the best example
of language design.
Ilkka Virta
2018-09-27 15:47:33 UTC
Permalink
Post by Greg Wooledge
Shift already takes one optional argument: the number of items to shift
from the argv list. Adding a second optional argument leads to a quagmire.
Do you put the optional list name first, or do you put the optional number
first? If only one argument is given, is it a list name, or is it a number?
(OK, granted, in bash it is not permitted to create an array whose name
is strictly digits, but still.)
Can you make an array whose name even starts with a digit?

With no overlap between array names and valid numbers,
shift [arrayname] [n] would be unambiguous, as you said.

Though shift [n [arrayname]] would be even more backward-compatible
since the new behaviour would always require two arguments, which is now
an error.


Even so, deciding how to handle sparse arrays might an interesting
issue, too.

If one wants a command that looks like the current shift, Dennis's
obvious slice-assignment could be wrapped in a function. Doing it this
way of course collapses the indices to consecutive numbers starting at zero.

ashift() {
typeset -n _arr_="$1";
_arr_=("${_arr_[@]:${2-1}}");
}
somearray=(a b c d)
ashift somearray 2
--
Ilkka Virta / ***@iki.fi
Greg Wooledge
2018-09-27 15:57:36 UTC
Permalink
Post by Ilkka Virta
Can you make an array whose name even starts with a digit?
No, that's also disallowed. Bash variable names (including arrays) must
begin with a letter or underscore.
L A Walsh
2018-09-27 17:56:45 UTC
Permalink
Post by Greg Wooledge
Post by L A Walsh
It struck me as it might be convenient if 'shift' could take an optional
arrayname as an argument. Would that be possible or would it cause some
incompatibility?
The biggest issue here is how you specify the arguments.
Shift already takes one optional argument: the number of items to shift
from the argv list. Adding a second optional argument leads to a quagmire.
Do you put the optional list name first, or do you put the optional number
first? If only one argument is given, is it a list name, or is it a number?
(OK, granted, in bash it is not permitted to create an array whose name
is strictly digits, but still.)
If you wish to write an array-shifting builtin, it would be better to give
it a new name. Don't blindly copy perl. It's not always the best example
of language design.
---
Why do you think I was blindly copying perl. My function example
was/is named lshift to differentiate it from rshift (if wanted),
but if it was a builtin there'd be no need for a different
name as it works and has compatible syntax with current 'shift'.

shift [N] ARRAYNAME. Without ARRAYNAME, it's is the 'shift [N]' that
is already in bash. There is no quagmire. If the parameter following
'shift'
is a number, it's a count. If it isn't a number, its an ID. Even
though my example and the subject showed the 'count' first, the order
really doesn't matter if you think about it...

Dennis Williamson
2018-09-27 12:42:20 UTC
Permalink
Post by L A Walsh
It struck me as it might be convenient if 'shift' could take an optional
arrayname as an argument. Would that be possible or would it cause some
incompatibility?
i.e.
set one two three four five
shift ARGV
two three four five
shift 2 ARGV
four five
I know it can be done with a function, but with more mess.
(in my lib file ArFuncs.shh, that I can include)
[include stdalias]
#[include Types] #if type-checking include Types+line below
lshift () {
(($#)) || return 1
int nshift=1
if [[ $1 =~ ^[0-9]+$ ]]; then nshift=$1; shift;fi
#if ! isArr $1; then echo >&2 "Need arrayname"; return 1; fi
my ar=$1; shift
set "${!h}"
shift $nshift
}; export -f lshift
"my" - What is this, Perl?
array_shift=2
arr=("${arr[@]:$array_shift}")

Done.
Chet Ramey
2018-09-27 14:20:31 UTC
Permalink
Post by Dennis Williamson
array_shift=2
Done.
This is the simplest and most elegant solution.
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU ***@case.edu http://tiswww.cwru.edu/~chet/
L A Walsh
2018-09-27 17:45:24 UTC
Permalink
Post by Dennis Williamson
Post by L A Walsh
[include stdalias]
#[include Types] #if type-checking include Types+line below
lshift () {
(($#)) || return 1
int nshift=1
if [[ $1 =~ ^[0-9]+$ ]]; then nshift=$1; shift;fi
#if ! isArr $1; then echo >&2 "Need arrayname"; return 1; fi
my ar=$1; shift
...
"my" - What is this, Perl?
Um...it's a "std" alias! :-)... It gets included from a bash
include file "stdalias.shh" the first time it is included.

It's really more perl than "int" (or "array" or "map")
that I use for other data types.

I certainly find 'my' and 'int' easier to type and read
than 'declare [-i]' or 'typeset [-i]'.

FWIW, if I wanted it to be more perl-like, I'd at least
use 'sub' before lshift (an alias for 'function') which
is slightly more clear than 'name()', as the empty
parens, at first glance, might indicate the function takes
no parameters, vs. being a syntax element. The parens are
slightly more concise, so I usually use them.
Post by Dennis Williamson
array_shift=2
---
I don't think I was aware that slicing syntax worked with arrays.

Certainly that's much more efficient (which was why I included my
code, cuz I figured my request was valid, OR there had to be a
tighter or better construct than what I'd thrown together
Post by Dennis Williamson
Done.
Much thanks! Your example certainly lessens the need for
shift to handle other arrays, although it still would be
a nice, simple and unambiguous syntax, though:

"shift 2 arr"

still looks simpler and clearer than slice syntax.
Loading...