How to get a bash script argument given its position from the end? [duplicate]











up vote
2
down vote

favorite
1













This question already has an answer here:




  • How to get the last argument to a /bin/sh function

    11 answers



  • Get last element of $@ / argv / arguments array without eval [duplicate]

    1 answer




I've got a shell script and I want to use the last argument:



#!/bin/bash
echo My last param is #somehow put it here


Here is what I've tried:



echo $$#
echo ${$#}
echo ${(($#))}


Unfortunately it did not work.



I'm specifically want to understand why my options did not work, I want to do something like double expansion.



In a broader sense, I would like to know how to access the Nth argument from the end. How do I achieve that?










share|improve this question















marked as duplicate by muru, Archemar, G-Man, telcoM, Anthony Geoghegan Dec 8 at 13:33


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.















  • Is your question for a solution specific to bash?.
    – Isaac
    Dec 8 at 1:42















up vote
2
down vote

favorite
1













This question already has an answer here:




  • How to get the last argument to a /bin/sh function

    11 answers



  • Get last element of $@ / argv / arguments array without eval [duplicate]

    1 answer




I've got a shell script and I want to use the last argument:



#!/bin/bash
echo My last param is #somehow put it here


Here is what I've tried:



echo $$#
echo ${$#}
echo ${(($#))}


Unfortunately it did not work.



I'm specifically want to understand why my options did not work, I want to do something like double expansion.



In a broader sense, I would like to know how to access the Nth argument from the end. How do I achieve that?










share|improve this question















marked as duplicate by muru, Archemar, G-Man, telcoM, Anthony Geoghegan Dec 8 at 13:33


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.















  • Is your question for a solution specific to bash?.
    – Isaac
    Dec 8 at 1:42













up vote
2
down vote

favorite
1









up vote
2
down vote

favorite
1






1






This question already has an answer here:




  • How to get the last argument to a /bin/sh function

    11 answers



  • Get last element of $@ / argv / arguments array without eval [duplicate]

    1 answer




I've got a shell script and I want to use the last argument:



#!/bin/bash
echo My last param is #somehow put it here


Here is what I've tried:



echo $$#
echo ${$#}
echo ${(($#))}


Unfortunately it did not work.



I'm specifically want to understand why my options did not work, I want to do something like double expansion.



In a broader sense, I would like to know how to access the Nth argument from the end. How do I achieve that?










share|improve this question
















This question already has an answer here:




  • How to get the last argument to a /bin/sh function

    11 answers



  • Get last element of $@ / argv / arguments array without eval [duplicate]

    1 answer




I've got a shell script and I want to use the last argument:



#!/bin/bash
echo My last param is #somehow put it here


Here is what I've tried:



echo $$#
echo ${$#}
echo ${(($#))}


Unfortunately it did not work.



I'm specifically want to understand why my options did not work, I want to do something like double expansion.



In a broader sense, I would like to know how to access the Nth argument from the end. How do I achieve that?





This question already has an answer here:




  • How to get the last argument to a /bin/sh function

    11 answers



  • Get last element of $@ / argv / arguments array without eval [duplicate]

    1 answer








shell-script shell






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 8 at 8:17

























asked Dec 7 at 19:51









YardenST

1606




1606




marked as duplicate by muru, Archemar, G-Man, telcoM, Anthony Geoghegan Dec 8 at 13:33


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.






marked as duplicate by muru, Archemar, G-Man, telcoM, Anthony Geoghegan Dec 8 at 13:33


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.














  • Is your question for a solution specific to bash?.
    – Isaac
    Dec 8 at 1:42


















  • Is your question for a solution specific to bash?.
    – Isaac
    Dec 8 at 1:42
















Is your question for a solution specific to bash?.
– Isaac
Dec 8 at 1:42




Is your question for a solution specific to bash?.
– Isaac
Dec 8 at 1:42










6 Answers
6






active

oldest

votes

















up vote
3
down vote



accepted










In addition (to Kusalananda's answer):



#! /bin/bash 

echo "(bash/ksh): ${@: -1}"
echo "(bash 3.x+): ${!#}"
echo "(bash 3.x+): $BASH_ARGV"
echo "(bash 3.x+/ksh): ${@:$#}"
echo "(bash 3.x+): ${BASH_ARGV[0]}"


and if you worry about portability:



#!/bin/bash

penultimate=''
ultimate=''

for p in "$@" ; do
penultimate="$ultimate"
ultimate="$p"
done

echo "penultimate=$penultimate"
echo "ultimate=$ultimate"





share|improve this answer























  • to Kusalananda's answer.
    – Ljm Dullaart
    Dec 7 at 20:24










  • Yes, you're right; I added it in the answer.
    – Ljm Dullaart
    Dec 7 at 20:26










  • can you please explain about this notation? ${!#}
    – YardenST
    Dec 7 at 21:22










  • @YardenST From the bash manpage: "If the first character of parameter is an exclamation point (!), and parameter is not a nameref, it introduces a level of variable indirection. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion."
    – JoL
    Dec 7 at 22:29








  • 1




    @YardenST Yes. Honestly, I think your attempts show what would have been the most obvious, intuitive syntax. I can only imagine ${!x} was chosen to intentionally limit the syntax to only allow 1 level of indirection instead of multiple by nesting, maybe to ease the implementation. There's probably other subtle reasons, though, like arguments about consistency and how it implies that other thing could also be nested.
    – JoL
    Dec 9 at 5:20




















up vote
5
down vote













To get any argument from bash script, you can use slicing:



#!/bin/bash

# Get 3rd element from the end
from_end1=3
# Get last element
from_end2=1

# Get slice of array [end - from_end1 : end ] of length 1
echo "${@: -$from_end1: 1}"
echo "${@: -$from_end2: 1}"


You can also use this to get Nth element:



# Get 2nd element
from_beginning=2

echo "${@: $from_beginning: 1}"


Remember to check for length; this might return your program's name or an empty string.






share|improve this answer



















  • 1




    This is bash-specific, right? You should probably note that since the OP's question did not mention bash except in the #! (and in particular didn't use bash tag).
    – R..
    Dec 8 at 0:10










  • @R.. Fair point, information added.
    – MatthewRock
    Dec 8 at 2:33


















up vote
4
down vote













In bash (release 4.3+), you may assign the passed parameters to an array and access the last one by the index -1:



#!/bin/bash

params=( "$@" )
printf 'The last parameter given to the script is %sn' "${params[-1]}"

foo () {
params=( "$@" )
printf 'The last parameter given to the function is %sn' "${params[-1]}"
}


In general, negative indexes into arrays accesses the elements from the end of the array.






share|improve this answer























  • A negative index might work on bash 4.2+ depending on the patch level. But an slice ${@: -1:1} works with negative indexes since bash 3.0.
    – Isaac
    Dec 8 at 3:12










  • @Isaac That's good if you are code golfing, but not if you're writing code that others need to understand and maintain.
    – Kusalananda
    Dec 8 at 8:19




















up vote
3
down vote













Portable sh, not bash-specific, and without O(n) loops:



eval x=$$(($#-1))


The -1 yields the penultimate argument; replace it with the position you want relative to the end, or drop it entirely if you want the very last one.






share|improve this answer



















  • 1




    One of the very few uses of eval I've ever seen that actually seems merited and safe.
    – Wildcard
    Dec 8 at 0:35










  • @Isaac: Updated to note that. Thanks.
    – R..
    Dec 8 at 1:57


















up vote
0
down vote













In zsh, the most natural thing, I think, would be:



echo "ultimate: ${@[$#]}"
echo "ultimate: ${@[-1]}"
echo "penultimate: ${@[-2]}"
echo "penultimate: ${@[$(($# - 1))]}"





share|improve this answer




























    up vote
    0
    down vote













    The clasic solutions for POSIX shells (which also work on ksh, zsh or bash) are:



     for last do :;done; echo "last=$last"
    eval "last=$$#"; echo "last=$last"


    For newer shells (ksh93,zsh,bash):



     echo "last=${@: -1}"
    echo "last=${@:(-1)}"
    echo "last=${@:~0}"
    echo "last=${@:$#}"


    Only for:



    bash echo "last=${!#}"
    bash echo "last=$BASH_ARGV"
    zsh echo "last=${@[-1]}"
    zsh echo "last=${@[#]}"



    For the penultimate argument:



     for arg do penultimate=$ultimate; ultimate=$arg; done; echo "$penultimate"
    eval penultimate=$$((#-1))
    echo "${@:$((#-1)):1}"
    echo "${@: -2:1}"
    echo "${@:~1:1}"





    share|improve this answer




























      6 Answers
      6






      active

      oldest

      votes








      6 Answers
      6






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      3
      down vote



      accepted










      In addition (to Kusalananda's answer):



      #! /bin/bash 

      echo "(bash/ksh): ${@: -1}"
      echo "(bash 3.x+): ${!#}"
      echo "(bash 3.x+): $BASH_ARGV"
      echo "(bash 3.x+/ksh): ${@:$#}"
      echo "(bash 3.x+): ${BASH_ARGV[0]}"


      and if you worry about portability:



      #!/bin/bash

      penultimate=''
      ultimate=''

      for p in "$@" ; do
      penultimate="$ultimate"
      ultimate="$p"
      done

      echo "penultimate=$penultimate"
      echo "ultimate=$ultimate"





      share|improve this answer























      • to Kusalananda's answer.
        – Ljm Dullaart
        Dec 7 at 20:24










      • Yes, you're right; I added it in the answer.
        – Ljm Dullaart
        Dec 7 at 20:26










      • can you please explain about this notation? ${!#}
        – YardenST
        Dec 7 at 21:22










      • @YardenST From the bash manpage: "If the first character of parameter is an exclamation point (!), and parameter is not a nameref, it introduces a level of variable indirection. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion."
        – JoL
        Dec 7 at 22:29








      • 1




        @YardenST Yes. Honestly, I think your attempts show what would have been the most obvious, intuitive syntax. I can only imagine ${!x} was chosen to intentionally limit the syntax to only allow 1 level of indirection instead of multiple by nesting, maybe to ease the implementation. There's probably other subtle reasons, though, like arguments about consistency and how it implies that other thing could also be nested.
        – JoL
        Dec 9 at 5:20

















      up vote
      3
      down vote



      accepted










      In addition (to Kusalananda's answer):



      #! /bin/bash 

      echo "(bash/ksh): ${@: -1}"
      echo "(bash 3.x+): ${!#}"
      echo "(bash 3.x+): $BASH_ARGV"
      echo "(bash 3.x+/ksh): ${@:$#}"
      echo "(bash 3.x+): ${BASH_ARGV[0]}"


      and if you worry about portability:



      #!/bin/bash

      penultimate=''
      ultimate=''

      for p in "$@" ; do
      penultimate="$ultimate"
      ultimate="$p"
      done

      echo "penultimate=$penultimate"
      echo "ultimate=$ultimate"





      share|improve this answer























      • to Kusalananda's answer.
        – Ljm Dullaart
        Dec 7 at 20:24










      • Yes, you're right; I added it in the answer.
        – Ljm Dullaart
        Dec 7 at 20:26










      • can you please explain about this notation? ${!#}
        – YardenST
        Dec 7 at 21:22










      • @YardenST From the bash manpage: "If the first character of parameter is an exclamation point (!), and parameter is not a nameref, it introduces a level of variable indirection. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion."
        – JoL
        Dec 7 at 22:29








      • 1




        @YardenST Yes. Honestly, I think your attempts show what would have been the most obvious, intuitive syntax. I can only imagine ${!x} was chosen to intentionally limit the syntax to only allow 1 level of indirection instead of multiple by nesting, maybe to ease the implementation. There's probably other subtle reasons, though, like arguments about consistency and how it implies that other thing could also be nested.
        – JoL
        Dec 9 at 5:20















      up vote
      3
      down vote



      accepted







      up vote
      3
      down vote



      accepted






      In addition (to Kusalananda's answer):



      #! /bin/bash 

      echo "(bash/ksh): ${@: -1}"
      echo "(bash 3.x+): ${!#}"
      echo "(bash 3.x+): $BASH_ARGV"
      echo "(bash 3.x+/ksh): ${@:$#}"
      echo "(bash 3.x+): ${BASH_ARGV[0]}"


      and if you worry about portability:



      #!/bin/bash

      penultimate=''
      ultimate=''

      for p in "$@" ; do
      penultimate="$ultimate"
      ultimate="$p"
      done

      echo "penultimate=$penultimate"
      echo "ultimate=$ultimate"





      share|improve this answer














      In addition (to Kusalananda's answer):



      #! /bin/bash 

      echo "(bash/ksh): ${@: -1}"
      echo "(bash 3.x+): ${!#}"
      echo "(bash 3.x+): $BASH_ARGV"
      echo "(bash 3.x+/ksh): ${@:$#}"
      echo "(bash 3.x+): ${BASH_ARGV[0]}"


      and if you worry about portability:



      #!/bin/bash

      penultimate=''
      ultimate=''

      for p in "$@" ; do
      penultimate="$ultimate"
      ultimate="$p"
      done

      echo "penultimate=$penultimate"
      echo "ultimate=$ultimate"






      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Dec 7 at 20:36









      Kusalananda

      120k16225370




      120k16225370










      answered Dec 7 at 20:18









      Ljm Dullaart

      59017




      59017












      • to Kusalananda's answer.
        – Ljm Dullaart
        Dec 7 at 20:24










      • Yes, you're right; I added it in the answer.
        – Ljm Dullaart
        Dec 7 at 20:26










      • can you please explain about this notation? ${!#}
        – YardenST
        Dec 7 at 21:22










      • @YardenST From the bash manpage: "If the first character of parameter is an exclamation point (!), and parameter is not a nameref, it introduces a level of variable indirection. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion."
        – JoL
        Dec 7 at 22:29








      • 1




        @YardenST Yes. Honestly, I think your attempts show what would have been the most obvious, intuitive syntax. I can only imagine ${!x} was chosen to intentionally limit the syntax to only allow 1 level of indirection instead of multiple by nesting, maybe to ease the implementation. There's probably other subtle reasons, though, like arguments about consistency and how it implies that other thing could also be nested.
        – JoL
        Dec 9 at 5:20




















      • to Kusalananda's answer.
        – Ljm Dullaart
        Dec 7 at 20:24










      • Yes, you're right; I added it in the answer.
        – Ljm Dullaart
        Dec 7 at 20:26










      • can you please explain about this notation? ${!#}
        – YardenST
        Dec 7 at 21:22










      • @YardenST From the bash manpage: "If the first character of parameter is an exclamation point (!), and parameter is not a nameref, it introduces a level of variable indirection. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion."
        – JoL
        Dec 7 at 22:29








      • 1




        @YardenST Yes. Honestly, I think your attempts show what would have been the most obvious, intuitive syntax. I can only imagine ${!x} was chosen to intentionally limit the syntax to only allow 1 level of indirection instead of multiple by nesting, maybe to ease the implementation. There's probably other subtle reasons, though, like arguments about consistency and how it implies that other thing could also be nested.
        – JoL
        Dec 9 at 5:20


















      to Kusalananda's answer.
      – Ljm Dullaart
      Dec 7 at 20:24




      to Kusalananda's answer.
      – Ljm Dullaart
      Dec 7 at 20:24












      Yes, you're right; I added it in the answer.
      – Ljm Dullaart
      Dec 7 at 20:26




      Yes, you're right; I added it in the answer.
      – Ljm Dullaart
      Dec 7 at 20:26












      can you please explain about this notation? ${!#}
      – YardenST
      Dec 7 at 21:22




      can you please explain about this notation? ${!#}
      – YardenST
      Dec 7 at 21:22












      @YardenST From the bash manpage: "If the first character of parameter is an exclamation point (!), and parameter is not a nameref, it introduces a level of variable indirection. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion."
      – JoL
      Dec 7 at 22:29






      @YardenST From the bash manpage: "If the first character of parameter is an exclamation point (!), and parameter is not a nameref, it introduces a level of variable indirection. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion."
      – JoL
      Dec 7 at 22:29






      1




      1




      @YardenST Yes. Honestly, I think your attempts show what would have been the most obvious, intuitive syntax. I can only imagine ${!x} was chosen to intentionally limit the syntax to only allow 1 level of indirection instead of multiple by nesting, maybe to ease the implementation. There's probably other subtle reasons, though, like arguments about consistency and how it implies that other thing could also be nested.
      – JoL
      Dec 9 at 5:20






      @YardenST Yes. Honestly, I think your attempts show what would have been the most obvious, intuitive syntax. I can only imagine ${!x} was chosen to intentionally limit the syntax to only allow 1 level of indirection instead of multiple by nesting, maybe to ease the implementation. There's probably other subtle reasons, though, like arguments about consistency and how it implies that other thing could also be nested.
      – JoL
      Dec 9 at 5:20














      up vote
      5
      down vote













      To get any argument from bash script, you can use slicing:



      #!/bin/bash

      # Get 3rd element from the end
      from_end1=3
      # Get last element
      from_end2=1

      # Get slice of array [end - from_end1 : end ] of length 1
      echo "${@: -$from_end1: 1}"
      echo "${@: -$from_end2: 1}"


      You can also use this to get Nth element:



      # Get 2nd element
      from_beginning=2

      echo "${@: $from_beginning: 1}"


      Remember to check for length; this might return your program's name or an empty string.






      share|improve this answer



















      • 1




        This is bash-specific, right? You should probably note that since the OP's question did not mention bash except in the #! (and in particular didn't use bash tag).
        – R..
        Dec 8 at 0:10










      • @R.. Fair point, information added.
        – MatthewRock
        Dec 8 at 2:33















      up vote
      5
      down vote













      To get any argument from bash script, you can use slicing:



      #!/bin/bash

      # Get 3rd element from the end
      from_end1=3
      # Get last element
      from_end2=1

      # Get slice of array [end - from_end1 : end ] of length 1
      echo "${@: -$from_end1: 1}"
      echo "${@: -$from_end2: 1}"


      You can also use this to get Nth element:



      # Get 2nd element
      from_beginning=2

      echo "${@: $from_beginning: 1}"


      Remember to check for length; this might return your program's name or an empty string.






      share|improve this answer



















      • 1




        This is bash-specific, right? You should probably note that since the OP's question did not mention bash except in the #! (and in particular didn't use bash tag).
        – R..
        Dec 8 at 0:10










      • @R.. Fair point, information added.
        – MatthewRock
        Dec 8 at 2:33













      up vote
      5
      down vote










      up vote
      5
      down vote









      To get any argument from bash script, you can use slicing:



      #!/bin/bash

      # Get 3rd element from the end
      from_end1=3
      # Get last element
      from_end2=1

      # Get slice of array [end - from_end1 : end ] of length 1
      echo "${@: -$from_end1: 1}"
      echo "${@: -$from_end2: 1}"


      You can also use this to get Nth element:



      # Get 2nd element
      from_beginning=2

      echo "${@: $from_beginning: 1}"


      Remember to check for length; this might return your program's name or an empty string.






      share|improve this answer














      To get any argument from bash script, you can use slicing:



      #!/bin/bash

      # Get 3rd element from the end
      from_end1=3
      # Get last element
      from_end2=1

      # Get slice of array [end - from_end1 : end ] of length 1
      echo "${@: -$from_end1: 1}"
      echo "${@: -$from_end2: 1}"


      You can also use this to get Nth element:



      # Get 2nd element
      from_beginning=2

      echo "${@: $from_beginning: 1}"


      Remember to check for length; this might return your program's name or an empty string.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Dec 8 at 2:32

























      answered Dec 7 at 20:06









      MatthewRock

      3,87821847




      3,87821847








      • 1




        This is bash-specific, right? You should probably note that since the OP's question did not mention bash except in the #! (and in particular didn't use bash tag).
        – R..
        Dec 8 at 0:10










      • @R.. Fair point, information added.
        – MatthewRock
        Dec 8 at 2:33














      • 1




        This is bash-specific, right? You should probably note that since the OP's question did not mention bash except in the #! (and in particular didn't use bash tag).
        – R..
        Dec 8 at 0:10










      • @R.. Fair point, information added.
        – MatthewRock
        Dec 8 at 2:33








      1




      1




      This is bash-specific, right? You should probably note that since the OP's question did not mention bash except in the #! (and in particular didn't use bash tag).
      – R..
      Dec 8 at 0:10




      This is bash-specific, right? You should probably note that since the OP's question did not mention bash except in the #! (and in particular didn't use bash tag).
      – R..
      Dec 8 at 0:10












      @R.. Fair point, information added.
      – MatthewRock
      Dec 8 at 2:33




      @R.. Fair point, information added.
      – MatthewRock
      Dec 8 at 2:33










      up vote
      4
      down vote













      In bash (release 4.3+), you may assign the passed parameters to an array and access the last one by the index -1:



      #!/bin/bash

      params=( "$@" )
      printf 'The last parameter given to the script is %sn' "${params[-1]}"

      foo () {
      params=( "$@" )
      printf 'The last parameter given to the function is %sn' "${params[-1]}"
      }


      In general, negative indexes into arrays accesses the elements from the end of the array.






      share|improve this answer























      • A negative index might work on bash 4.2+ depending on the patch level. But an slice ${@: -1:1} works with negative indexes since bash 3.0.
        – Isaac
        Dec 8 at 3:12










      • @Isaac That's good if you are code golfing, but not if you're writing code that others need to understand and maintain.
        – Kusalananda
        Dec 8 at 8:19

















      up vote
      4
      down vote













      In bash (release 4.3+), you may assign the passed parameters to an array and access the last one by the index -1:



      #!/bin/bash

      params=( "$@" )
      printf 'The last parameter given to the script is %sn' "${params[-1]}"

      foo () {
      params=( "$@" )
      printf 'The last parameter given to the function is %sn' "${params[-1]}"
      }


      In general, negative indexes into arrays accesses the elements from the end of the array.






      share|improve this answer























      • A negative index might work on bash 4.2+ depending on the patch level. But an slice ${@: -1:1} works with negative indexes since bash 3.0.
        – Isaac
        Dec 8 at 3:12










      • @Isaac That's good if you are code golfing, but not if you're writing code that others need to understand and maintain.
        – Kusalananda
        Dec 8 at 8:19















      up vote
      4
      down vote










      up vote
      4
      down vote









      In bash (release 4.3+), you may assign the passed parameters to an array and access the last one by the index -1:



      #!/bin/bash

      params=( "$@" )
      printf 'The last parameter given to the script is %sn' "${params[-1]}"

      foo () {
      params=( "$@" )
      printf 'The last parameter given to the function is %sn' "${params[-1]}"
      }


      In general, negative indexes into arrays accesses the elements from the end of the array.






      share|improve this answer














      In bash (release 4.3+), you may assign the passed parameters to an array and access the last one by the index -1:



      #!/bin/bash

      params=( "$@" )
      printf 'The last parameter given to the script is %sn' "${params[-1]}"

      foo () {
      params=( "$@" )
      printf 'The last parameter given to the function is %sn' "${params[-1]}"
      }


      In general, negative indexes into arrays accesses the elements from the end of the array.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Dec 7 at 21:05

























      answered Dec 7 at 20:03









      Kusalananda

      120k16225370




      120k16225370












      • A negative index might work on bash 4.2+ depending on the patch level. But an slice ${@: -1:1} works with negative indexes since bash 3.0.
        – Isaac
        Dec 8 at 3:12










      • @Isaac That's good if you are code golfing, but not if you're writing code that others need to understand and maintain.
        – Kusalananda
        Dec 8 at 8:19




















      • A negative index might work on bash 4.2+ depending on the patch level. But an slice ${@: -1:1} works with negative indexes since bash 3.0.
        – Isaac
        Dec 8 at 3:12










      • @Isaac That's good if you are code golfing, but not if you're writing code that others need to understand and maintain.
        – Kusalananda
        Dec 8 at 8:19


















      A negative index might work on bash 4.2+ depending on the patch level. But an slice ${@: -1:1} works with negative indexes since bash 3.0.
      – Isaac
      Dec 8 at 3:12




      A negative index might work on bash 4.2+ depending on the patch level. But an slice ${@: -1:1} works with negative indexes since bash 3.0.
      – Isaac
      Dec 8 at 3:12












      @Isaac That's good if you are code golfing, but not if you're writing code that others need to understand and maintain.
      – Kusalananda
      Dec 8 at 8:19






      @Isaac That's good if you are code golfing, but not if you're writing code that others need to understand and maintain.
      – Kusalananda
      Dec 8 at 8:19












      up vote
      3
      down vote













      Portable sh, not bash-specific, and without O(n) loops:



      eval x=$$(($#-1))


      The -1 yields the penultimate argument; replace it with the position you want relative to the end, or drop it entirely if you want the very last one.






      share|improve this answer



















      • 1




        One of the very few uses of eval I've ever seen that actually seems merited and safe.
        – Wildcard
        Dec 8 at 0:35










      • @Isaac: Updated to note that. Thanks.
        – R..
        Dec 8 at 1:57















      up vote
      3
      down vote













      Portable sh, not bash-specific, and without O(n) loops:



      eval x=$$(($#-1))


      The -1 yields the penultimate argument; replace it with the position you want relative to the end, or drop it entirely if you want the very last one.






      share|improve this answer



















      • 1




        One of the very few uses of eval I've ever seen that actually seems merited and safe.
        – Wildcard
        Dec 8 at 0:35










      • @Isaac: Updated to note that. Thanks.
        – R..
        Dec 8 at 1:57













      up vote
      3
      down vote










      up vote
      3
      down vote









      Portable sh, not bash-specific, and without O(n) loops:



      eval x=$$(($#-1))


      The -1 yields the penultimate argument; replace it with the position you want relative to the end, or drop it entirely if you want the very last one.






      share|improve this answer














      Portable sh, not bash-specific, and without O(n) loops:



      eval x=$$(($#-1))


      The -1 yields the penultimate argument; replace it with the position you want relative to the end, or drop it entirely if you want the very last one.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Dec 8 at 1:57

























      answered Dec 8 at 0:14









      R..

      1,85611014




      1,85611014








      • 1




        One of the very few uses of eval I've ever seen that actually seems merited and safe.
        – Wildcard
        Dec 8 at 0:35










      • @Isaac: Updated to note that. Thanks.
        – R..
        Dec 8 at 1:57














      • 1




        One of the very few uses of eval I've ever seen that actually seems merited and safe.
        – Wildcard
        Dec 8 at 0:35










      • @Isaac: Updated to note that. Thanks.
        – R..
        Dec 8 at 1:57








      1




      1




      One of the very few uses of eval I've ever seen that actually seems merited and safe.
      – Wildcard
      Dec 8 at 0:35




      One of the very few uses of eval I've ever seen that actually seems merited and safe.
      – Wildcard
      Dec 8 at 0:35












      @Isaac: Updated to note that. Thanks.
      – R..
      Dec 8 at 1:57




      @Isaac: Updated to note that. Thanks.
      – R..
      Dec 8 at 1:57










      up vote
      0
      down vote













      In zsh, the most natural thing, I think, would be:



      echo "ultimate: ${@[$#]}"
      echo "ultimate: ${@[-1]}"
      echo "penultimate: ${@[-2]}"
      echo "penultimate: ${@[$(($# - 1))]}"





      share|improve this answer

























        up vote
        0
        down vote













        In zsh, the most natural thing, I think, would be:



        echo "ultimate: ${@[$#]}"
        echo "ultimate: ${@[-1]}"
        echo "penultimate: ${@[-2]}"
        echo "penultimate: ${@[$(($# - 1))]}"





        share|improve this answer























          up vote
          0
          down vote










          up vote
          0
          down vote









          In zsh, the most natural thing, I think, would be:



          echo "ultimate: ${@[$#]}"
          echo "ultimate: ${@[-1]}"
          echo "penultimate: ${@[-2]}"
          echo "penultimate: ${@[$(($# - 1))]}"





          share|improve this answer












          In zsh, the most natural thing, I think, would be:



          echo "ultimate: ${@[$#]}"
          echo "ultimate: ${@[-1]}"
          echo "penultimate: ${@[-2]}"
          echo "penultimate: ${@[$(($# - 1))]}"






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Dec 7 at 22:21









          JoL

          987310




          987310






















              up vote
              0
              down vote













              The clasic solutions for POSIX shells (which also work on ksh, zsh or bash) are:



               for last do :;done; echo "last=$last"
              eval "last=$$#"; echo "last=$last"


              For newer shells (ksh93,zsh,bash):



               echo "last=${@: -1}"
              echo "last=${@:(-1)}"
              echo "last=${@:~0}"
              echo "last=${@:$#}"


              Only for:



              bash echo "last=${!#}"
              bash echo "last=$BASH_ARGV"
              zsh echo "last=${@[-1]}"
              zsh echo "last=${@[#]}"



              For the penultimate argument:



               for arg do penultimate=$ultimate; ultimate=$arg; done; echo "$penultimate"
              eval penultimate=$$((#-1))
              echo "${@:$((#-1)):1}"
              echo "${@: -2:1}"
              echo "${@:~1:1}"





              share|improve this answer

























                up vote
                0
                down vote













                The clasic solutions for POSIX shells (which also work on ksh, zsh or bash) are:



                 for last do :;done; echo "last=$last"
                eval "last=$$#"; echo "last=$last"


                For newer shells (ksh93,zsh,bash):



                 echo "last=${@: -1}"
                echo "last=${@:(-1)}"
                echo "last=${@:~0}"
                echo "last=${@:$#}"


                Only for:



                bash echo "last=${!#}"
                bash echo "last=$BASH_ARGV"
                zsh echo "last=${@[-1]}"
                zsh echo "last=${@[#]}"



                For the penultimate argument:



                 for arg do penultimate=$ultimate; ultimate=$arg; done; echo "$penultimate"
                eval penultimate=$$((#-1))
                echo "${@:$((#-1)):1}"
                echo "${@: -2:1}"
                echo "${@:~1:1}"





                share|improve this answer























                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  The clasic solutions for POSIX shells (which also work on ksh, zsh or bash) are:



                   for last do :;done; echo "last=$last"
                  eval "last=$$#"; echo "last=$last"


                  For newer shells (ksh93,zsh,bash):



                   echo "last=${@: -1}"
                  echo "last=${@:(-1)}"
                  echo "last=${@:~0}"
                  echo "last=${@:$#}"


                  Only for:



                  bash echo "last=${!#}"
                  bash echo "last=$BASH_ARGV"
                  zsh echo "last=${@[-1]}"
                  zsh echo "last=${@[#]}"



                  For the penultimate argument:



                   for arg do penultimate=$ultimate; ultimate=$arg; done; echo "$penultimate"
                  eval penultimate=$$((#-1))
                  echo "${@:$((#-1)):1}"
                  echo "${@: -2:1}"
                  echo "${@:~1:1}"





                  share|improve this answer












                  The clasic solutions for POSIX shells (which also work on ksh, zsh or bash) are:



                   for last do :;done; echo "last=$last"
                  eval "last=$$#"; echo "last=$last"


                  For newer shells (ksh93,zsh,bash):



                   echo "last=${@: -1}"
                  echo "last=${@:(-1)}"
                  echo "last=${@:~0}"
                  echo "last=${@:$#}"


                  Only for:



                  bash echo "last=${!#}"
                  bash echo "last=$BASH_ARGV"
                  zsh echo "last=${@[-1]}"
                  zsh echo "last=${@[#]}"



                  For the penultimate argument:



                   for arg do penultimate=$ultimate; ultimate=$arg; done; echo "$penultimate"
                  eval penultimate=$$((#-1))
                  echo "${@:$((#-1)):1}"
                  echo "${@: -2:1}"
                  echo "${@:~1:1}"






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Dec 8 at 2:14









                  Isaac

                  11k11648




                  11k11648















                      Popular posts from this blog

                      Probability when a professor distributes a quiz and homework assignment to a class of n students.

                      Aardman Animations

                      Are they similar matrix