0

I checked the /usr/bin/ssh-copy-id(part of openssh-client package at least under Debian) shell-script and it contains following if-statement:

if [ "-i" = "$1" ]; then
  shift
  # check if we have 2 parameters left, if so the first is the new ID file
  if [ -n "$2" ]; then
    if expr "$1" : ".*\.pub" > /dev/null ; then
      ID_FILE="$1"
    else
      ID_FILE="$1.pub"
    fi
    shift         # and this should leave $1 as the target name
  fi
else

What is the point of shift commands? I mean I know that shift n shell builtin shifts n number of arguments from left to right, but what is the reason to use it in this script? Why not use:

if [ "-i" = "$1" ]; then
  if [ -n "$3" ]; then
    if expr "$2" : ".*\.pub" > /dev/null ; then
      ID_FILE="$2"
    else
      ID_FILE="$2.pub"
    fi
  fi
  • 1
    I'm assuming these arguments are actually going somewhere else at some point, right? And anyway, you and the script author both could benefit from a case statement here. – mikeserv Jun 25 '15 at 22:05
7

What do you do after you've parsed the -i option? There are more arguments to parse. If -i was the first argument, then after processing it, you need to look at the third argument. In the old version of ssh-copy-id you're looking at, -i is the sole option and the argument after that is the target host name. If -i is not passed, the target host name is the first argument.

if [ "$1" = "-i" ]; then
  …
  target_host_name=$3
else
  target_host_name=$1
fi

This doesn't scale when there are multiple options. You'd need to keep track of the current position in the argument list.

if [ "${$position}" = "-i" ]; then
  …
  position=$((position+2))
fi
target_host_name=${$position}

The thing is, what I wrote here is not valid shell syntax. There's no easy construct to get the nth argument; you can do it with eval, but it's awkward, and antique shells couldn't deal with multi-digit argument numbers.

So instead, each time an option is processed, it's removed from the list, by calling shift. If the option has an argument, call shift 2, or call shift a second time to remove the option argument. Then after processing each option, the next argument to process is always $1. It's simpler that way.

if [ "$1" = "-i" ]; then
  …
  shift 2
fi
…
target_host_name=$1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.