9

Is it possible to unset the $1 variable? If not, I can't find out where it is explained in man.

[root@centos2 ~]# set bon jour
[root@centos2 ~]# echo $1$2
bonjour
[root@centos2 ~]# unset $1
[root@centos2 ~]# echo $1$2
bonjour
[root@centos2 ~]#

EDIT:

Finaly, here is what I found out in man (man set option double-dash) to empty all the positional parameters (and the man used the word "unset"!):

If no arguments follow this option, then the positional parameters are unset.

[root@centos2 ~]# echo $1

[root@centos2 ~]# set bon jour
[root@centos2 ~]# echo $1$2
bonjour
[root@centos2 ~]# set --
[root@centos2 ~]# echo $1$2

[root@centos2 ~]#

It's @Jeff Schaller's answer that helped me understand that.

psmears
  • 461
  • 3
  • 8
Pozinux
  • 1,305
  • 5
  • 16
  • 27
  • 4
    I'm not sure what you're asking but you could use 'shift' to make $2 take the place of $1, therefore removing $1. EDIT: Kusalananda has a more expansive answer below. – bitofagoob May 17 '17 at 20:45
  • You are right my question is not well formed. I was looking for how to empty a positional variable if I had set it. – Pozinux May 17 '17 at 21:25

4 Answers4

21

You can't unset a positional parameter, but you may shift $2 into $1, effectively removing the old value of $2.

$ set -- bon jour
$ echo "$1$2"
bonjour

$ shift
$ echo "$1$2"  # $2 is now empty (i.e. "unset" or "not set")
jour

The shift command will shift all positional parameters one step lower. Command-line parsing loops (that does not use getopt/getopts) commonly shift the positional parameters over each iteration while repeatedly examining the value of $1. It is uncommon to want to unset a positional parameter.

By the way, unset takes a variable name, not its value, so unset $1 will, in effect, unset the variable bon (had it been previously set).

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • What about if I want to empty $1? Also, good point on the fact that it would be `unset bon`. I didn't think about that. – Pozinux May 17 '17 at 21:30
  • @Pozinux That would be quite an unusual thing to want to do. What is the issue you're trying to solve? – Kusalananda May 17 '17 at 21:33
  • In fact, I'm learning. I'was trying to understand how `set`works. I tried this example with "bonjour" but couldn't find a way how to empty this variable. I mixed a bit with unset. Probably because I did't get yet all the concept about set, unset, env, export etc. – Pozinux May 17 '17 at 21:36
  • 1
    @Pozinux Well, setting them _again_ would overwrite them, like Jeff shows in his answer. – Kusalananda May 17 '17 at 21:39
  • When you use `getopt` or `getopts` you _do_ use `shift`. – Dennis Williamson May 18 '17 at 20:55
  • @DennisWilliamson Not while parsing the option and their arguments. If you want to get at the operands afterwards, then yes, you may want to `shift $((OPTIND - 1))`. – Kusalananda May 18 '17 at 21:32
16

You could empty it, by re-setting the parameters to: "the empty string" followed by "the parameters, starting from the 2nd one":

$ set -- 1 2 3 4
$ printf -- "->%s<-\n" "$@"
->1<-
->2<-
->3<-
->4<-
$ set -- "" "${@:2}"
$ printf -- "->%s<-\n" "$@"
-><-
->2<-
->3<-
->4<-
Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
  • Your anwser is nice and right aswell but it took me more time to understand it because of my little shell level... In fact, it helped me to find out about the "--" option that I didn't know (see my edit on my question). Thanks. – Pozinux May 18 '17 at 17:05
6

Besides all the correct technical answers you should notice that there is a logical flaw in your question. $1, $2,... are not the values of named variables like $A, $B, ..., but the 1st, 2nd,... value of a list of values. Maybe the first value of a list is an empty string but it does not make sense to say my list has no first value. If a list has no first value then it has no value at all and so it is an empty list.

So you cannot "unset" the first value of a list. You can only remove the first value from a list. Then the former 2nd value of the list is now the 1st value of the list, the former 3rd is now the 2nd and so on. This is exactly what the shift operator does.

miracle173
  • 503
  • 2
  • 12
  • Though note that actual _arrays_ don't need to be indexed consecutively from zero, you could go `unset A; A[4]=foo; A[7]=bar;` and leave with `A[0]` among others unset (not just empty). And then `unset A[4]`. But I'm digressing, this doesn't apply to the positional parameters. – ilkkachu May 18 '17 at 11:26
  • @miracle173, you are right it doesn't make sense. I thought that unset was also used to empty a variable. – Pozinux May 18 '17 at 11:49
  • @ilkkachu A is an array and not a list of values. A[0], A[1], ... are similar to variables and therefore can be empty – miracle173 May 18 '17 at 12:48
4

No, at least not directly. This syntax should work but yields an error:

$ set bon jour
$ echo $1 $2
$ unset 1
1: not a valid identifier

unset $variable is usually a mistake and unset variable was what was intended. Unfortunately it doesn't work here.

Joshua
  • 1,733
  • 12
  • 19