help-bash
[Top][All Lists]
Advanced

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

Re: idea about negative indexed array keys


From: Greg Wooledge
Subject: Re: idea about negative indexed array keys
Date: Sun, 14 Mar 2021 13:14:53 -0400

On Sun, Mar 14, 2021 at 11:46:51AM +0100, Alex fxmbsw7 Ratchev wrote:
> i know which it was
> 
> it was shift -1
> to shift from the end
> 
> is there a way to do so ? just wondering

Your Subject: header still contains the phrase "indexed array" so I'm
going to start with those.

The only way to remove the largest-indexed element of an array is to
determine what that index is, and then use unset.  (Other approaches
would require reconstructing the entire array, so I'm not counting those.)

If you're trying to use an array to implement a stack, the unset
approach is highly viable.  I recommend keeping a second variable that
holds the largest index at any given time.

E.g.

unicorn:~$ pop() { r=${stack[n]}; unset 'stack[n--]'; }
unicorn:~$ push() { stack[++n]="$1"; }
unicorn:~$ push foo; push bar; push baz; pop; echo "$r"; declare -p stack n
baz
declare -a stack=([1]="foo" [2]="bar")
declare -- n="2"

This works because the "stack" is under your control at all times.  If
you poke at the array without calling "pop" or "push", however, all bets
are off.

(In a real script, I would use a different variable name than "n" to
hold the stack's highest index.  And probably add some error checking,
for the case where you try to pop from an empty stack.)

If you're not trying to implement a stack, then tell us what you're
trying to do.

----

Now, let's explore the case where the Subject: header doesn't talk about
indexed arrays.  You imply that you're trying to remove the last
positional parameter given to a script.  We might guess that you're
trying to implement a wrapper around cp, or something like that, where
the final argument is treated specially.

The literal answer to your question is: no.  No, you cannot "shift from
the end".

How, then, would one implement a script that works like cp, performing
pre-checks on the final argument?

One way is to use bash's indirection feature to get the final argument.

n=$#
lastarg=${!n}

This doesn't alter the positional parameters, of course.  But then we can
also use bash's parameter expansion syntax to rewrite the positional
parameters:

set -- "${@:1:n-1}"

This copies the entire argument list at least once, probably more than
once, so it's expensive.  Oh well.  This is bash, and if you wanted speed,
you'd be writing in some other language.

If you aren't trying to implement a script that works like cp, then tell
us what you're trying to do.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]