You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by el...@apache.org on 2014/04/08 05:03:25 UTC

[29/53] [abbrv] Revert "ACCUMULO-1897 Move shell into new package and module"

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/OfflineCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/OfflineCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/OfflineCommand.java
new file mode 100644
index 0000000..fde4514
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/OfflineCommand.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.metadata.MetadataTable;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class OfflineCommand extends TableOperation {
+  
+  private boolean wait;
+  private Option waitOpt;
+  
+  @Override
+  public String description() {
+    return "starts the process of taking table offline";
+  }
+  
+  protected void doTableOp(final Shell shellState, final String tableName) throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
+    if (tableName.equals(MetadataTable.NAME)) {
+      Shell.log.info("  You cannot take the " + MetadataTable.NAME + " offline.");
+    } else {
+      shellState.getConnector().tableOperations().offline(tableName, wait);
+      Shell.log.info("Offline of table " + tableName + (wait ? " completed." : " initiated..."));
+    }
+  }
+  
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+    wait = cl.hasOption(waitOpt.getLongOpt());
+    return super.execute(fullCommand, cl, shellState);
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options opts = super.getOptions();
+    waitOpt = new Option("w", "wait", false, "wait for offline to finish");
+    opts.addOption(waitOpt); 
+    return opts;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/OnlineCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/OnlineCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/OnlineCommand.java
new file mode 100644
index 0000000..7b6ebe2
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/OnlineCommand.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.metadata.RootTable;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class OnlineCommand extends TableOperation {
+  
+  private boolean wait;
+  private Option waitOpt;
+  
+  @Override
+  public String description() {
+    return "starts the process of putting a table online";
+  }
+  
+  @Override
+  protected void doTableOp(final Shell shellState, final String tableName) throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
+    if (tableName.equals(RootTable.NAME)) {
+      Shell.log.info("  The " + RootTable.NAME + " is always online.");
+    } else {
+      shellState.getConnector().tableOperations().online(tableName, wait);
+      Shell.log.info("Online of table " + tableName + (wait ? " completed." : " initiated..."));
+    }
+  }
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+    wait = cl.hasOption(waitOpt.getLongOpt());
+    return super.execute(fullCommand, cl, shellState);
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options opts = super.getOptions();
+    waitOpt = new Option("w", "wait", false, "wait for online to finish");
+    opts.addOption(waitOpt); 
+    return opts;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/OptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/OptUtil.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/OptUtil.java
new file mode 100644
index 0000000..9915bdf
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/OptUtil.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.NamespaceNotFoundException;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionGroup;
+import org.apache.hadoop.io.Text;
+
+public abstract class OptUtil {
+  public static final String START_ROW_OPT = "b";
+  public static final String END_ROW_OPT = "e";
+
+  public static String getTableOpt(final CommandLine cl, final Shell shellState) throws TableNotFoundException {
+    String tableName;
+
+    if (cl.hasOption(Shell.tableOption)) {
+      tableName = cl.getOptionValue(Shell.tableOption);
+      if (!shellState.getConnector().tableOperations().exists(tableName)) {
+        throw new TableNotFoundException(tableName, tableName, "specified table that doesn't exist");
+      }
+    } else {
+      shellState.checkTableState();
+      tableName = shellState.getTableName();
+    }
+
+    return tableName;
+  }
+
+  public static String getNamespaceOpt(final CommandLine cl, final Shell shellState) throws NamespaceNotFoundException, AccumuloException,
+      AccumuloSecurityException {
+    String namespace = null;
+    if (cl.hasOption(Shell.namespaceOption)) {
+      namespace = cl.getOptionValue(Shell.namespaceOption);
+      if (!shellState.getConnector().namespaceOperations().exists(namespace)) {
+        throw new NamespaceNotFoundException(namespace, namespace, "specified namespace that doesn't exist");
+      }
+    } else {
+      throw new NamespaceNotFoundException(null, null, "no namespace specified");
+    }
+    return namespace;
+  }
+
+  public static Option tableOpt() {
+    return tableOpt("tableName");
+  }
+
+  public static Option tableOpt(final String description) {
+    final Option tableOpt = new Option(Shell.tableOption, "table", true, description);
+    tableOpt.setArgName("table");
+    tableOpt.setRequired(false);
+    return tableOpt;
+  }
+
+  public static Option namespaceOpt() {
+    return namespaceOpt("namespace");
+  }
+
+  public static Option namespaceOpt(final String description) {
+    final Option namespaceOpt = new Option(Shell.namespaceOption, "namespace", true, description);
+    namespaceOpt.setArgName("namespace");
+    namespaceOpt.setRequired(false);
+    return namespaceOpt;
+  }
+
+  public static enum AdlOpt {
+    ADD("a"), DELETE("d"), LIST("l");
+
+    public final String opt;
+
+    private AdlOpt(String opt) {
+      this.opt = opt;
+    }
+  }
+
+  public static AdlOpt getAldOpt(final CommandLine cl) {
+    if (cl.hasOption(AdlOpt.ADD.opt)) {
+      return AdlOpt.ADD;
+    } else if (cl.hasOption(AdlOpt.DELETE.opt)) {
+      return AdlOpt.DELETE;
+    } else {
+      return AdlOpt.LIST;
+    }
+  }
+
+  public static OptionGroup addListDeleteGroup(final String name) {
+    final Option addOpt = new Option(AdlOpt.ADD.opt, "add", false, "add " + name);
+    final Option deleteOpt = new Option(AdlOpt.DELETE.opt, "delete", false, "delete " + name);
+    final Option listOpt = new Option(AdlOpt.LIST.opt, "list", false, "list " + name + "(s)");
+    final OptionGroup og = new OptionGroup();
+    og.addOption(addOpt);
+    og.addOption(deleteOpt);
+    og.addOption(listOpt);
+    og.setRequired(true);
+    return og;
+  }
+
+  public static Option startRowOpt() {
+    final Option o = new Option(START_ROW_OPT, "begin-row", true, "begin row (inclusive)");
+    o.setArgName("begin-row");
+    return o;
+  }
+
+  public static Option endRowOpt() {
+    final Option o = new Option(END_ROW_OPT, "end-row", true, "end row (inclusive)");
+    o.setArgName("end-row");
+    return o;
+  }
+
+  public static Text getStartRow(final CommandLine cl) throws UnsupportedEncodingException {
+    if (cl.hasOption(START_ROW_OPT)) {
+      return new Text(cl.getOptionValue(START_ROW_OPT).getBytes(Shell.CHARSET));
+    } else {
+      return null;
+    }
+  }
+
+  public static Text getEndRow(final CommandLine cl) throws UnsupportedEncodingException {
+    if (cl.hasOption(END_ROW_OPT)) {
+      return new Text(cl.getOptionValue(END_ROW_OPT).getBytes(Shell.CHARSET));
+    } else {
+      return null;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/PasswdCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/PasswdCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/PasswdCommand.java
new file mode 100644
index 0000000..86446a2
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/PasswdCommand.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode;
+import org.apache.accumulo.core.client.security.tokens.PasswordToken;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class PasswdCommand extends Command {
+  private Option userOpt;
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException, IOException {
+    final String currentUser = shellState.getConnector().whoami();
+    final String user = cl.getOptionValue(userOpt.getOpt(), currentUser);
+    
+    String password = null;
+    String passwordConfirm = null;
+    String oldPassword = null;
+    
+    oldPassword = shellState.readMaskedLine("Enter current password for '" + currentUser + "': ", '*');
+    if (oldPassword == null) {
+      shellState.getReader().println();
+      return 0;
+    } // user canceled
+    
+    if (!shellState.getConnector().securityOperations().authenticateUser(currentUser, new PasswordToken(oldPassword)))
+      throw new AccumuloSecurityException(user, SecurityErrorCode.BAD_CREDENTIALS);
+    
+    password = shellState.readMaskedLine("Enter new password for '" + user + "': ", '*');
+    if (password == null) {
+      shellState.getReader().println();
+      return 0;
+    } // user canceled
+    passwordConfirm = shellState.readMaskedLine("Please confirm new password for '" + user + "': ", '*');
+    if (passwordConfirm == null) {
+      shellState.getReader().println();
+      return 0;
+    } // user canceled
+    
+    if (!password.equals(passwordConfirm)) {
+      throw new IllegalArgumentException("Passwords do not match");
+    }
+    byte[] pass = password.getBytes(StandardCharsets.UTF_8);
+    shellState.getConnector().securityOperations().changeLocalUserPassword(user, new PasswordToken(pass));
+    // update the current credentials if the password changed was for
+    // the current user
+    if (shellState.getConnector().whoami().equals(user)) {
+      shellState.updateUser(user, new PasswordToken(pass));
+    }
+    Shell.log.debug("Changed password for user " + user);
+    return 0;
+  }
+  
+  @Override
+  public String description() {
+    return "changes a user's password";
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options o = new Options();
+    userOpt = new Option(Shell.userOption, "user", true, "user to operate on");
+    userOpt.setArgName("user");
+    o.addOption(userOpt);
+    return o;
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/PingCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/PingCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/PingCommand.java
new file mode 100644
index 0000000..d0eb615
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/PingCommand.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.accumulo.core.client.admin.InstanceOperations;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+/**
+ * 
+ */
+public class PingCommand extends Command {
+  
+  private Option tserverOption, disablePaginationOpt;
+  
+  @Override
+  public String description() {
+    return "ping tablet servers";
+  }
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+    
+    List<String> tservers;
+    
+    final InstanceOperations instanceOps = shellState.getConnector().instanceOperations();
+    
+    final boolean paginate = !cl.hasOption(disablePaginationOpt.getOpt());
+    
+    if (cl.hasOption(tserverOption.getOpt())) {
+      tservers = new ArrayList<String>();
+      tservers.add(cl.getOptionValue(tserverOption.getOpt()));
+    } else {
+      tservers = instanceOps.getTabletServers();
+    }
+    
+    shellState.printLines(new PingIterator(tservers, instanceOps), paginate);
+    
+    return 0;
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options opts = new Options();
+    
+    tserverOption = new Option("ts", "tabletServer", true, "tablet server to ping");
+    tserverOption.setArgName("tablet server");
+    opts.addOption(tserverOption);
+    
+    disablePaginationOpt = new Option("np", "no-pagination", false, "disable pagination of output");
+    opts.addOption(disablePaginationOpt);
+    
+    return opts;
+  }
+  
+}
+

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/PingIterator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/PingIterator.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/PingIterator.java
new file mode 100644
index 0000000..2a1020e
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/PingIterator.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.admin.InstanceOperations;
+
+class PingIterator implements Iterator<String> {
+  
+  private Iterator<String> iter;
+  private InstanceOperations instanceOps;
+
+  PingIterator(List<String> tservers, InstanceOperations instanceOps) {
+    iter = tservers.iterator();
+    this.instanceOps = instanceOps;
+  }
+  
+  @Override
+  public boolean hasNext() {
+    return iter.hasNext();
+  }
+  
+  @Override
+  public String next() {
+    String tserver = iter.next();
+    
+    try {
+      instanceOps.ping(tserver);
+    } catch (AccumuloException e) {
+      return tserver + " ERROR " + e.getMessage();
+    }
+    
+    return tserver + " OK";
+  }
+  
+  @Override
+  public void remove() {
+    throw new UnsupportedOperationException();
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/QuestionCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/QuestionCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/QuestionCommand.java
new file mode 100644
index 0000000..b12c2cb
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/QuestionCommand.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+public class QuestionCommand extends HelpCommand {
+  @Override
+  public String getName() {
+    return "?";
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/QuitCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/QuitCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/QuitCommand.java
new file mode 100644
index 0000000..8aa95f5
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/QuitCommand.java
@@ -0,0 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+public class QuitCommand extends ExitCommand {}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/QuotedStringTokenizer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/QuotedStringTokenizer.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/QuotedStringTokenizer.java
new file mode 100644
index 0000000..76ebb8f
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/QuotedStringTokenizer.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.apache.accumulo.core.util.BadArgumentException;
+import org.apache.accumulo.core.util.shell.Shell;
+
+/**
+ * A basic tokenizer for generating tokens from a string. It understands quoted strings and escaped quote characters.
+ * 
+ * You can use the escape sequence '\' to escape single quotes, double quotes, and spaces only, in addition to the escape character itself.
+ * 
+ * The behavior is the same for single and double quoted strings. (i.e. '\'' is the same as "\'")
+ */
+
+public class QuotedStringTokenizer implements Iterable<String> {
+  private ArrayList<String> tokens;
+  private String input;
+  
+  public QuotedStringTokenizer(final String t) throws BadArgumentException {
+    tokens = new ArrayList<String>();
+    this.input = t;
+    try {
+      createTokens();
+    } catch (UnsupportedEncodingException e) {
+      throw new IllegalArgumentException(e.getMessage());
+    }
+  }
+  
+  public String[] getTokens() {
+    return tokens.toArray(new String[tokens.size()]);
+  }
+  
+  private void createTokens() throws BadArgumentException, UnsupportedEncodingException {
+    boolean inQuote = false;
+    boolean inEscapeSequence = false;
+    String hexChars = null;
+    char inQuoteChar = '"';
+    
+    final byte[] token = new byte[input.length()];
+    int tokenLength = 0;
+    final byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
+    for (int i = 0; i < input.length(); ++i) {
+      final char ch = input.charAt(i);
+      
+      // if I ended up in an escape sequence, check for valid escapable character, and add it as a literal
+      if (inEscapeSequence) {
+        inEscapeSequence = false;
+        if (ch == 'x') {
+          hexChars = "";
+        } else if (ch == ' ' || ch == '\'' || ch == '"' || ch == '\\') {
+          token[tokenLength++] = inputBytes[i];
+        } else {
+          throw new BadArgumentException("can only escape single quotes, double quotes, the space character, the backslash, and hex input", input, i);
+        }
+      }
+      // in a hex escape sequence
+      else if (hexChars != null) {
+        final int digit = Character.digit(ch, 16);
+        if (digit < 0) {
+          throw new BadArgumentException("expected hex character", input, i);
+        }
+        hexChars += ch;
+        if (hexChars.length() == 2) {
+          byte b;
+          try {
+            b = (byte) (0xff & Short.parseShort(hexChars, 16));
+            if (!Character.isValidCodePoint(0xff & b))
+              throw new NumberFormatException();
+          } catch (NumberFormatException e) {
+            throw new BadArgumentException("unsupported non-ascii character", input, i);
+          }
+          token[tokenLength++] = b;
+          hexChars = null;
+        }
+      }
+      // in a quote, either end the quote, start escape, or continue a token
+      else if (inQuote) {
+        if (ch == inQuoteChar) {
+          inQuote = false;
+          tokens.add(new String(token, 0, tokenLength, Shell.CHARSET));
+          tokenLength = 0;
+        } else if (ch == '\\') {
+          inEscapeSequence = true;
+        } else {
+          token[tokenLength++] = inputBytes[i];
+        }
+      }
+      // not in a quote, either enter a quote, end a token, start escape, or continue a token
+      else {
+        if (ch == '\'' || ch == '"') {
+          if (tokenLength > 0) {
+            tokens.add(new String(token, 0, tokenLength, Shell.CHARSET));
+            tokenLength = 0;
+          }
+          inQuote = true;
+          inQuoteChar = ch;
+        } else if (ch == ' ' && tokenLength > 0) {
+          tokens.add(new String(token, 0, tokenLength, Shell.CHARSET));
+          tokenLength = 0;
+        } else if (ch == '\\') {
+          inEscapeSequence = true;
+        } else if (ch != ' ') {
+          token[tokenLength++] = inputBytes[i];
+        }
+      }
+    }
+    if (inQuote) {
+      throw new BadArgumentException("missing terminating quote", input, input.length());
+    } else if (inEscapeSequence || hexChars != null) {
+      throw new BadArgumentException("escape sequence not complete", input, input.length());
+    }
+    if (tokenLength > 0) {
+      tokens.add(new String(token, 0, tokenLength, Shell.CHARSET));
+    }
+  }
+  
+  @Override
+  public Iterator<String> iterator() {
+    return tokens.iterator();
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RenameNamespaceCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RenameNamespaceCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RenameNamespaceCommand.java
new file mode 100644
index 0000000..d7ff7c3
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RenameNamespaceCommand.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.NamespaceExistsException;
+import org.apache.accumulo.core.client.NamespaceNotFoundException;
+import org.apache.accumulo.core.client.TableExistsException;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.client.impl.Namespaces;
+import org.apache.accumulo.core.client.impl.Tables;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.accumulo.core.util.shell.Token;
+import org.apache.commons.cli.CommandLine;
+
+public class RenameNamespaceCommand extends Command {
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException,
+      TableNotFoundException, TableExistsException, NamespaceNotFoundException, NamespaceExistsException {
+    String old = cl.getArgs()[0];
+    String newer = cl.getArgs()[1];
+    boolean resetContext = false;
+    String currentTableId = "";
+    if (!(shellState.getTableName() == null) && !shellState.getTableName().isEmpty()) {
+      String namespaceId = Namespaces.getNamespaceId(shellState.getInstance(), old);
+      List<String> tableIds = Namespaces.getTableIds(shellState.getInstance(), namespaceId);
+      currentTableId = Tables.getTableId(shellState.getInstance(), shellState.getTableName());
+      resetContext = tableIds.contains(currentTableId);
+    }
+
+    shellState.getConnector().namespaceOperations().rename(old, newer);
+
+    if (resetContext) {
+      shellState.setTableName(Tables.getTableName(shellState.getInstance(), currentTableId));
+    }
+
+    return 0;
+  }
+
+  @Override
+  public String usage() {
+    return getName() + " <current namespace> <new namespace>";
+  }
+
+  @Override
+  public String description() {
+    return "renames a namespace";
+  }
+
+  @Override
+  public void registerCompletion(final Token root, final Map<Command.CompletionSet,Set<String>> special) {
+    registerCompletionForNamespaces(root, special);
+  }
+
+  @Override
+  public int numArgs() {
+    return 2;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RenameTableCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RenameTableCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RenameTableCommand.java
new file mode 100644
index 0000000..38d8158
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RenameTableCommand.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.TableExistsException;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.client.impl.Tables;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.accumulo.core.util.shell.Token;
+import org.apache.commons.cli.CommandLine;
+
+public class RenameTableCommand extends Command {
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException,
+      TableNotFoundException, TableExistsException {
+    shellState.getConnector().tableOperations().rename(cl.getArgs()[0], cl.getArgs()[1]);
+    if (shellState.getTableName().equals(Tables.qualified(cl.getArgs()[0]))) {
+      shellState.setTableName(cl.getArgs()[1]);
+    }
+    return 0;
+  }
+
+  @Override
+  public String usage() {
+    return getName() + " <current table name> <new table name>";
+  }
+
+  @Override
+  public String description() {
+    return "renames a table";
+  }
+
+  @Override
+  public void registerCompletion(final Token root, final Map<Command.CompletionSet,Set<String>> completionSet) {
+    registerCompletionForTables(root, completionSet);
+  }
+
+  @Override
+  public int numArgs() {
+    return 2;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RevokeCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RevokeCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RevokeCommand.java
new file mode 100644
index 0000000..dac864d
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RevokeCommand.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.accumulo.core.security.NamespacePermission;
+import org.apache.accumulo.core.security.SystemPermission;
+import org.apache.accumulo.core.security.TablePermission;
+import org.apache.accumulo.core.util.BadArgumentException;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.accumulo.core.util.shell.Token;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionGroup;
+import org.apache.commons.cli.Options;
+
+public class RevokeCommand extends TableOperation {
+  {
+    disableUnflaggedTableOptions();
+  }
+
+  private Option systemOpt, userOpt;
+  private String user;
+  private String[] permission;
+
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+    user = cl.hasOption(userOpt.getOpt()) ? cl.getOptionValue(userOpt.getOpt()) : shellState.getConnector().whoami();
+
+    permission = cl.getArgs()[0].split("\\.", 2);
+    if (cl.hasOption(systemOpt.getOpt()) && permission[0].equalsIgnoreCase("System")) {
+      try {
+        shellState.getConnector().securityOperations().revokeSystemPermission(user, SystemPermission.valueOf(permission[1]));
+        Shell.log.debug("Revoked from " + user + " the " + permission[1] + " permission");
+      } catch (IllegalArgumentException e) {
+        throw new BadArgumentException("No such system permission", fullCommand, fullCommand.indexOf(cl.getArgs()[0]));
+      }
+    } else if (permission[0].equalsIgnoreCase("Table")) {
+      super.execute(fullCommand, cl, shellState);
+    } else if (permission[0].equalsIgnoreCase("Namespace")) {
+      if (cl.hasOption(optNamespace.getOpt())) {
+        try {
+          shellState.getConnector().securityOperations()
+              .revokeNamespacePermission(user, cl.getOptionValue(optNamespace.getOpt()), NamespacePermission.valueOf(permission[1]));
+        } catch (IllegalArgumentException e) {
+          throw new BadArgumentException("No such namespace permission", fullCommand, fullCommand.indexOf(cl.getArgs()[0]));
+        }
+      } else {
+        throw new BadArgumentException("No namespace specified to apply permission to", fullCommand, fullCommand.indexOf(cl.getArgs()[0]));
+      }
+    } else {
+      throw new BadArgumentException("Unrecognized permission", fullCommand, fullCommand.indexOf(cl.getArgs()[0]));
+    }
+    return 0;
+  }
+
+  @Override
+  protected void doTableOp(final Shell shellState, final String tableName) throws Exception {
+    try {
+      shellState.getConnector().securityOperations().revokeTablePermission(user, tableName, TablePermission.valueOf(permission[1]));
+      Shell.log.debug("Revoked from " + user + " the " + permission[1] + " permission on table " + tableName);
+    } catch (IllegalArgumentException e) {
+      throw new IllegalArgumentException("No such table permission", e);
+    }
+  }
+
+  @Override
+  public String description() {
+    return "revokes system or table permissions from a user";
+  }
+
+  @Override
+  public String usage() {
+    return getName() + " <permission>";
+  }
+
+  @Override
+  public void registerCompletion(final Token root, final Map<Command.CompletionSet,Set<String>> completionSet) {
+    final Token cmd = new Token(getName());
+    cmd.addSubcommand(new Token(TablePermission.printableValues()));
+    cmd.addSubcommand(new Token(SystemPermission.printableValues()));
+    cmd.addSubcommand(new Token(NamespacePermission.printableValues()));
+    root.addSubcommand(cmd);
+  }
+
+  @Override
+  public Options getOptions() {
+    super.getOptions();
+    final Options o = new Options();
+
+    final OptionGroup group = new OptionGroup();
+
+    systemOpt = new Option("s", "system", false, "revoke a system permission");
+
+    optNamespace = new Option(Shell.namespaceOption, "namespace", true, "name of a namespace to operate on");
+    optNamespace.setArgName("namespace");
+
+    group.addOption(systemOpt);
+    group.addOption(optTableName);
+    group.addOption(optTablePattern);
+    group.addOption(optNamespace);
+
+    o.addOptionGroup(group);
+    userOpt = new Option(Shell.userOption, "user", true, "user to operate on");
+    userOpt.setArgName("username");
+    userOpt.setRequired(true);
+    o.addOption(userOpt);
+
+    return o;
+  }
+
+  @Override
+  public int numArgs() {
+    return 1;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ScanCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ScanCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ScanCommand.java
new file mode 100644
index 0000000..f3a0663
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ScanCommand.java
@@ -0,0 +1,334 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.IteratorSetting;
+import org.apache.accumulo.core.client.Scanner;
+import org.apache.accumulo.core.client.ScannerBase;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.Value;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.util.format.BinaryFormatter;
+import org.apache.accumulo.core.util.format.Formatter;
+import org.apache.accumulo.core.util.interpret.DefaultScanInterpreter;
+import org.apache.accumulo.core.util.interpret.ScanInterpreter;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.accumulo.core.util.shell.Shell.PrintFile;
+import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.hadoop.io.Text;
+
+public class ScanCommand extends Command {
+  
+  private Option scanOptAuths, scanOptRow, scanOptColumns, disablePaginationOpt, showFewOpt, formatterOpt, interpreterOpt, formatterInterpeterOpt,
+      outputFileOpt;
+  
+  protected Option timestampOpt;
+  private Option optStartRowExclusive;
+  private Option optEndRowExclusive;
+  private Option timeoutOption;
+  private Option profileOpt;
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+    final PrintFile printFile = getOutputFile(cl);
+    final String tableName = OptUtil.getTableOpt(cl, shellState);
+    
+    final Class<? extends Formatter> formatter = getFormatter(cl, tableName, shellState);
+    final ScanInterpreter interpeter = getInterpreter(cl, tableName, shellState);
+    
+    // handle first argument, if present, the authorizations list to
+    // scan with
+    final Authorizations auths = getAuths(cl, shellState);
+    final Scanner scanner = shellState.getConnector().createScanner(tableName, auths);
+    
+    // handle session-specific scan iterators
+    addScanIterators(shellState, cl, scanner, tableName);
+    
+    // handle remaining optional arguments
+    scanner.setRange(getRange(cl, interpeter));
+    
+    // handle columns
+    fetchColumns(cl, scanner, interpeter);
+    
+    // set timeout
+    scanner.setTimeout(getTimeout(cl), TimeUnit.MILLISECONDS);
+    
+    // output the records
+    if (cl.hasOption(showFewOpt.getOpt())) {
+      final String showLength = cl.getOptionValue(showFewOpt.getOpt());
+      try {
+        final int length = Integer.parseInt(showLength);
+        if (length < 1) {
+          throw new IllegalArgumentException();
+        }
+        BinaryFormatter.getlength(length);
+        printBinaryRecords(cl, shellState, scanner, printFile);
+      } catch (NumberFormatException nfe) {
+        shellState.getReader().println("Arg must be an integer.");
+      } catch (IllegalArgumentException iae) {
+        shellState.getReader().println("Arg must be greater than one.");
+      }
+      
+    } else {
+      printRecords(cl, shellState, scanner, formatter, printFile);
+    }
+    if (printFile != null) {
+      printFile.close();
+    }
+    
+    return 0;
+  }
+  
+  protected long getTimeout(final CommandLine cl) {
+    if (cl.hasOption(timeoutOption.getLongOpt())) {
+      return AccumuloConfiguration.getTimeInMillis(cl.getOptionValue(timeoutOption.getLongOpt()));
+    }
+    
+    return Long.MAX_VALUE;
+  }
+  
+  protected void addScanIterators(final Shell shellState, CommandLine cl, final Scanner scanner, final String tableName) {
+    
+    List<IteratorSetting> tableScanIterators;
+    if (cl.hasOption(profileOpt.getOpt())) {
+      String profile = cl.getOptionValue(profileOpt.getOpt());
+      tableScanIterators = shellState.iteratorProfiles.get(profile);
+      
+      if (tableScanIterators == null) {
+        throw new IllegalArgumentException("Profile " + profile + " does not exist");
+      }
+    } else {
+      tableScanIterators = shellState.scanIteratorOptions.get(tableName);
+      if (tableScanIterators == null) {
+        Shell.log.debug("Found no scan iterators to set");
+        return;
+      }
+    }
+    
+    Shell.log.debug("Found " + tableScanIterators.size() + " scan iterators to set");
+    
+    for (IteratorSetting setting : tableScanIterators) {
+      Shell.log.debug("Setting scan iterator " + setting.getName() + " at priority " + setting.getPriority() + " using class name "
+          + setting.getIteratorClass());
+      for (Entry<String,String> option : setting.getOptions().entrySet()) {
+        Shell.log.debug("Setting option for " + setting.getName() + ": " + option.getKey() + "=" + option.getValue());
+      }
+      scanner.addScanIterator(setting);
+    }
+  }
+  
+  protected void printRecords(final CommandLine cl, final Shell shellState, final Iterable<Entry<Key,Value>> scanner, final Class<? extends Formatter> formatter)
+      throws IOException {
+    printRecords(cl, shellState, scanner, formatter, null);
+  }
+  
+  protected void printRecords(final CommandLine cl, final Shell shellState, final Iterable<Entry<Key,Value>> scanner,
+      final Class<? extends Formatter> formatter, PrintFile outFile) throws IOException {
+    if (outFile == null) {
+      shellState.printRecords(scanner, cl.hasOption(timestampOpt.getOpt()), !cl.hasOption(disablePaginationOpt.getOpt()), formatter);
+    } else {
+      shellState.printRecords(scanner, cl.hasOption(timestampOpt.getOpt()), !cl.hasOption(disablePaginationOpt.getOpt()), formatter, outFile);
+    }
+  }
+  
+  protected void printBinaryRecords(final CommandLine cl, final Shell shellState, final Iterable<Entry<Key,Value>> scanner) throws IOException {
+    printBinaryRecords(cl, shellState, scanner, null);
+  }
+  
+  protected void printBinaryRecords(final CommandLine cl, final Shell shellState, final Iterable<Entry<Key,Value>> scanner, PrintFile outFile)
+      throws IOException {
+    if (outFile == null) {
+      shellState.printBinaryRecords(scanner, cl.hasOption(timestampOpt.getOpt()), !cl.hasOption(disablePaginationOpt.getOpt()));
+    } else {
+      shellState.printBinaryRecords(scanner, cl.hasOption(timestampOpt.getOpt()), !cl.hasOption(disablePaginationOpt.getOpt()), outFile);
+    }
+  }
+  
+  protected ScanInterpreter getInterpreter(final CommandLine cl, final String tableName, final Shell shellState) throws Exception {
+    
+    Class<? extends ScanInterpreter> clazz = null;
+    try {
+      if (cl.hasOption(interpreterOpt.getOpt())) {
+        clazz = AccumuloVFSClassLoader.loadClass(cl.getOptionValue(interpreterOpt.getOpt()), ScanInterpreter.class);
+      } else if (cl.hasOption(formatterInterpeterOpt.getOpt())) {
+        clazz = AccumuloVFSClassLoader.loadClass(cl.getOptionValue(formatterInterpeterOpt.getOpt()), ScanInterpreter.class);
+      }
+    } catch (ClassNotFoundException e) {
+      shellState.getReader().println("Interpreter class could not be loaded.\n" + e.getMessage());
+    }
+    
+    if (clazz == null)
+      clazz = InterpreterCommand.getCurrentInterpreter(tableName, shellState);
+    
+    if (clazz == null)
+      clazz = DefaultScanInterpreter.class;
+    
+    return clazz.newInstance();
+  }
+  
+  protected Class<? extends Formatter> getFormatter(final CommandLine cl, final String tableName, final Shell shellState) throws IOException {
+    
+    try {
+      if (cl.hasOption(formatterOpt.getOpt())) {
+        return AccumuloVFSClassLoader.loadClass(cl.getOptionValue(formatterOpt.getOpt()), Formatter.class);
+        
+      } else if (cl.hasOption(formatterInterpeterOpt.getOpt())) {
+        return AccumuloVFSClassLoader.loadClass(cl.getOptionValue(formatterInterpeterOpt.getOpt()), Formatter.class);
+      }
+    } catch (ClassNotFoundException e) {
+      shellState.getReader().println("Formatter class could not be loaded.\n" + e.getMessage());
+    }
+    
+    return shellState.getFormatter(tableName);
+  }
+  
+  protected void fetchColumns(final CommandLine cl, final ScannerBase scanner, final ScanInterpreter formatter) throws UnsupportedEncodingException {
+    if (cl.hasOption(scanOptColumns.getOpt())) {
+      for (String a : cl.getOptionValue(scanOptColumns.getOpt()).split(",")) {
+        final String sa[] = a.split(":", 2);
+        if (sa.length == 1) {
+          scanner.fetchColumnFamily(formatter.interpretColumnFamily(new Text(a.getBytes(Shell.CHARSET))));
+        } else {
+          scanner.fetchColumn(formatter.interpretColumnFamily(new Text(sa[0].getBytes(Shell.CHARSET))),
+              formatter.interpretColumnQualifier(new Text(sa[1].getBytes(Shell.CHARSET))));
+        }
+      }
+    }
+  }
+  
+  protected Range getRange(final CommandLine cl, final ScanInterpreter formatter) throws UnsupportedEncodingException {
+    if ((cl.hasOption(OptUtil.START_ROW_OPT) || cl.hasOption(OptUtil.END_ROW_OPT)) && cl.hasOption(scanOptRow.getOpt())) {
+      // did not see a way to make commons cli do this check... it has mutually exclusive options but does not support the or
+      throw new IllegalArgumentException("Options -" + scanOptRow.getOpt() + " AND (-" + OptUtil.START_ROW_OPT + " OR -" + OptUtil.END_ROW_OPT
+          + ") are mutally exclusive ");
+    }
+    
+    if (cl.hasOption(scanOptRow.getOpt())) {
+      return new Range(formatter.interpretRow(new Text(cl.getOptionValue(scanOptRow.getOpt()).getBytes(Shell.CHARSET))));
+    } else {
+      Text startRow = OptUtil.getStartRow(cl);
+      if (startRow != null)
+        startRow = formatter.interpretBeginRow(startRow);
+      Text endRow = OptUtil.getEndRow(cl);
+      if (endRow != null)
+        endRow = formatter.interpretEndRow(endRow);
+      final boolean startInclusive = !cl.hasOption(optStartRowExclusive.getOpt());
+      final boolean endInclusive = !cl.hasOption(optEndRowExclusive.getOpt());
+      return new Range(startRow, startInclusive, endRow, endInclusive);
+    }
+  }
+  
+  protected Authorizations getAuths(final CommandLine cl, final Shell shellState) throws AccumuloSecurityException, AccumuloException {
+    final String user = shellState.getConnector().whoami();
+    Authorizations auths = shellState.getConnector().securityOperations().getUserAuthorizations(user);
+    if (cl.hasOption(scanOptAuths.getOpt())) {
+      auths = ScanCommand.parseAuthorizations(cl.getOptionValue(scanOptAuths.getOpt()));
+    }
+    return auths;
+  }
+  
+  static Authorizations parseAuthorizations(final String field) {
+    if (field == null || field.isEmpty()) {
+      return Authorizations.EMPTY;
+    }
+    return new Authorizations(field.split(","));
+  }
+  
+  @Override
+  public String description() {
+    return "scans the table, and displays the resulting records";
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options o = new Options();
+    
+    scanOptAuths = new Option("s", "scan-authorizations", true, "scan authorizations (all user auths are used if this argument is not specified)");
+    optStartRowExclusive = new Option("be", "begin-exclusive", false, "make start row exclusive (by default it's inclusive)");
+    optStartRowExclusive.setArgName("begin-exclusive");
+    optEndRowExclusive = new Option("ee", "end-exclusive", false, "make end row exclusive (by default it's inclusive)");
+    optEndRowExclusive.setArgName("end-exclusive");
+    scanOptRow = new Option("r", "row", true, "row to scan");
+    scanOptColumns = new Option("c", "columns", true, "comma-separated columns");
+    timestampOpt = new Option("st", "show-timestamps", false, "display timestamps");
+    disablePaginationOpt = new Option("np", "no-pagination", false, "disable pagination of output");
+    showFewOpt = new Option("f", "show few", true, "show only a specified number of characters");
+    formatterOpt = new Option("fm", "formatter", true, "fully qualified name of the formatter class to use");
+    interpreterOpt = new Option("i", "interpreter", true, "fully qualified name of the interpreter class to use");
+    formatterInterpeterOpt = new Option("fi", "fmt-interpreter", true, "fully qualified name of a class that is a formatter and interpreter");
+    timeoutOption = new Option(null, "timeout", true,
+        "time before scan should fail if no data is returned. If no unit is given assumes seconds.  Units d,h,m,s,and ms are supported.  e.g. 30s or 100ms");
+    outputFileOpt = new Option("o", "output", true, "local file to write the scan output to");
+    
+    scanOptAuths.setArgName("comma-separated-authorizations");
+    scanOptRow.setArgName("row");
+    scanOptColumns.setArgName("<columnfamily>[:<columnqualifier>]{,<columnfamily>[:<columnqualifier>]}");
+    showFewOpt.setRequired(false);
+    showFewOpt.setArgName("int");
+    formatterOpt.setArgName("className");
+    timeoutOption.setArgName("timeout");
+    outputFileOpt.setArgName("file");
+    
+    profileOpt = new Option("pn", "profile", true, "iterator profile name");
+    profileOpt.setArgName("profile");
+    
+    o.addOption(scanOptAuths);
+    o.addOption(scanOptRow);
+    o.addOption(OptUtil.startRowOpt());
+    o.addOption(OptUtil.endRowOpt());
+    o.addOption(optStartRowExclusive);
+    o.addOption(optEndRowExclusive);
+    o.addOption(scanOptColumns);
+    o.addOption(timestampOpt);
+    o.addOption(disablePaginationOpt);
+    o.addOption(OptUtil.tableOpt("table to be scanned"));
+    o.addOption(showFewOpt);
+    o.addOption(formatterOpt);
+    o.addOption(interpreterOpt);
+    o.addOption(formatterInterpeterOpt);
+    o.addOption(timeoutOption);
+    o.addOption(outputFileOpt);
+    o.addOption(profileOpt);
+    
+    return o;
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+  
+  protected PrintFile getOutputFile(final CommandLine cl) throws FileNotFoundException {
+    final String outputFile = cl.getOptionValue(outputFileOpt.getOpt());
+    return (outputFile == null ? null : new PrintFile(outputFile));
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ScriptCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ScriptCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ScriptCommand.java
new file mode 100644
index 0000000..5a0eee0
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ScriptCommand.java
@@ -0,0 +1,290 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.script.Bindings;
+import javax.script.Compilable;
+import javax.script.CompiledScript;
+import javax.script.Invocable;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import javax.script.SimpleScriptContext;
+
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionGroup;
+import org.apache.commons.cli.Options;
+
+public class ScriptCommand extends Command {
+  
+  // Command to allow user to run scripts, see JSR-223
+  // http://www.oracle.com/technetwork/articles/javase/scripting-140262.html
+  
+  protected Option list, engine, script, file, args, out, function, object;
+  private static final String DEFAULT_ENGINE = "rhino";
+  
+  public int execute(String fullCommand, CommandLine cl, Shell shellState) throws Exception {
+
+    boolean invoke = false;
+    ScriptEngineManager mgr = new ScriptEngineManager();
+    
+    if (cl.hasOption(list.getOpt())) {
+      listJSREngineInfo(mgr, shellState);
+    } else if (cl.hasOption(file.getOpt()) || cl.hasOption(script.getOpt())) {
+      String engineName = DEFAULT_ENGINE;
+      if (cl.hasOption(engine.getOpt())) {
+        engineName = cl.getOptionValue(engine.getOpt());
+      }
+      ScriptEngine engine = mgr.getEngineByName(engineName);
+      if (null == engine) {
+        shellState.printException(new Exception(engineName + " not found"));
+        return 1;
+      }
+      
+      if (cl.hasOption(object.getOpt()) || cl.hasOption(function.getOpt())) {
+        if (!(engine instanceof Invocable)) {
+          shellState.printException(new Exception(engineName + " does not support invoking functions or methods"));
+          return 1;
+        }
+        invoke = true;
+      }
+      
+      ScriptContext ctx = new SimpleScriptContext();
+      
+      // Put the following objects into the context so that they
+      // are available to the scripts
+      // TODO: What else should go in here?
+      Bindings b = engine.getBindings(ScriptContext.ENGINE_SCOPE);
+      b.put("connection", shellState.getConnector());
+      
+      List<Object> argValues = new ArrayList<Object>();
+      if (cl.hasOption(args.getOpt())) {
+        String[] argList = cl.getOptionValue(args.getOpt()).split(",");
+        for (String arg : argList) {
+          String[] parts = arg.split("=");
+          if (parts.length == 0) {
+            continue;
+          } else if (parts.length == 1) {
+            b.put(parts[0], null);
+            argValues.add(null);
+          } else if (parts.length == 2) {
+            b.put(parts[0], parts[1]);
+            argValues.add(parts[1]);
+          }
+        }
+      }
+      ctx.setBindings(b, ScriptContext.ENGINE_SCOPE);
+      Object[] argArray = argValues.toArray(new Object[argValues.size()]);
+      
+      Writer writer = null;
+      if (cl.hasOption(out.getOpt())) {
+        File f = new File(cl.getOptionValue(out.getOpt()));
+        writer = new FileWriter(f);
+        ctx.setWriter(writer);
+      }
+      
+      if (cl.hasOption(file.getOpt())) {
+        File f = new File(cl.getOptionValue(file.getOpt()));
+        if (!f.exists()) {
+          if (null != writer) {
+            writer.close();
+          }
+          shellState.printException(new Exception(f.getAbsolutePath() + " not found"));
+          return 1;
+        }
+        Reader reader = new FileReader(f);
+        try {
+          engine.eval(reader, ctx);
+          if (invoke) {
+            this.invokeFunctionOrMethod(shellState, engine, cl, argArray);
+          }
+        } catch (ScriptException ex) {
+          shellState.printException(ex);
+          return 1;
+        } finally {
+          reader.close();
+          if (null != writer) {
+            writer.close();
+          }
+        }
+      } else if (cl.hasOption(script.getOpt())) {
+        String inlineScript = cl.getOptionValue(script.getOpt());
+        try {
+          if (engine instanceof Compilable) {
+            Compilable compiledEng = (Compilable) engine;
+            CompiledScript script = compiledEng.compile(inlineScript);
+            script.eval(ctx);
+            if (invoke) {
+              this.invokeFunctionOrMethod(shellState, engine, cl, argArray);
+            }
+          } else {
+            engine.eval(inlineScript, ctx);
+            if (invoke) {
+              this.invokeFunctionOrMethod(shellState, engine, cl, argArray);
+            }
+          }
+        } catch (ScriptException ex) {
+          shellState.printException(ex);
+          return 1;
+        } finally {
+          if (null != writer) {
+            writer.close();
+          }
+        }
+      }
+      if (null != writer) {
+        writer.close();
+      }
+      
+    } else {
+      printHelp(shellState);
+    }
+    return 0;
+  }
+  
+  public String description() {
+    return "execute JSR-223 scripts";
+  }
+  
+  public int numArgs() {
+    return 0;
+  }
+  
+  @Override
+  public String getName() {
+    return "script";
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options o = new Options();
+    
+    engine = new Option("e", "engine", false, "engine name, defaults to JDK default (Rhino)");
+    engine.setArgName("engineName");
+    engine.setArgs(1);
+    engine.setRequired(false);
+    o.addOption(engine);
+    
+    OptionGroup inputGroup = new OptionGroup();
+    list = new Option("l", "list", false, "list available script engines");
+    inputGroup.addOption(list);
+
+    script = new Option("s", "script", true, "use inline script");
+    script.setArgName("script text");
+    script.setArgs(1);
+    script.setRequired(false);
+    inputGroup.addOption(script);
+    
+    file = new Option("f", "file", true, "use script file");
+    file.setArgName("fileName");
+    file.setArgs(1);
+    file.setRequired(false);
+    
+    inputGroup.addOption(file);
+    inputGroup.setRequired(true);
+    o.addOptionGroup(inputGroup);
+    
+    OptionGroup invokeGroup = new OptionGroup();
+    object = new Option("obj", "object", true, "name of object");
+    object.setArgs(1);
+    object.setArgName("objectName:methodName");
+    object.setRequired(false);
+    invokeGroup.addOption(object);
+    
+    function = new Option("fx", "function", true, "invoke a script function");
+    function.setArgName("functionName");
+    function.setArgs(1);
+    function.setRequired(false);
+    invokeGroup.addOption(function);
+    invokeGroup.setRequired(false);
+    o.addOptionGroup(invokeGroup);
+    
+    args = new Option("a", "args", true, "comma separated list of key=value arguments");
+    args.setArgName("property1=value1,propert2=value2,...");
+    args.setArgs(Option.UNLIMITED_VALUES);
+    args.setRequired(false);
+    o.addOption(args);
+    
+    out = new Option("o", "output", true, "output file");
+    out.setArgName("fileName");
+    out.setArgs(1);
+    out.setRequired(false);
+    o.addOption(out);
+    
+    return o;
+  }
+  
+  private void listJSREngineInfo(ScriptEngineManager mgr, Shell shellState) throws IOException {
+    List<ScriptEngineFactory> factories = mgr.getEngineFactories();
+    Set<String> lines = new TreeSet<String>();
+    for (ScriptEngineFactory factory : factories) {
+      lines.add("ScriptEngineFactory Info");
+      String engName = factory.getEngineName();
+      String engVersion = factory.getEngineVersion();
+      String langName = factory.getLanguageName();
+      String langVersion = factory.getLanguageVersion();
+      lines.add("\tScript Engine: " + engName + " (" + engVersion + ")");
+      List<String> engNames = factory.getNames();
+      for (String name : engNames) {
+        lines.add("\tEngine Alias: " + name);
+      }
+      lines.add("\tLanguage: " + langName + " (" + langVersion + ")");
+    }
+    shellState.printLines(lines.iterator(), true);
+    
+  }
+  
+  private void invokeFunctionOrMethod(Shell shellState, ScriptEngine engine, CommandLine cl, Object[] args) {
+    try {
+      Invocable inv = (Invocable) engine;
+      if (cl.hasOption(function.getOpt())) {
+        inv.invokeFunction(cl.getOptionValue(function.getOpt()), args);
+      } else if (cl.hasOption(object.getOpt())) {
+        String objectMethod = cl.getOptionValue(object.getOpt());
+        String[] parts = objectMethod.split(":");
+        if (!(parts.length == 2)) {
+          shellState.printException(new Exception("Object and Method must be supplied"));
+          return;
+        }
+        String objectName = parts[0];
+        String methodName = parts[1];
+        Object obj = engine.get(objectName);
+        inv.invokeMethod(obj, methodName, args);
+        
+      }
+    } catch (Exception e) {
+      shellState.printException(e);
+    }
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/SetAuthsCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/SetAuthsCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/SetAuthsCommand.java
new file mode 100644
index 0000000..256720c
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/SetAuthsCommand.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.accumulo.core.util.shell.Token;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionGroup;
+import org.apache.commons.cli.Options;
+
+public class SetAuthsCommand extends Command {
+  private Option userOpt;
+  private Option scanOptAuths;
+  private Option clearOptAuths;
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException {
+    final String user = cl.getOptionValue(userOpt.getOpt(), shellState.getConnector().whoami());
+    final String scanOpts = cl.hasOption(clearOptAuths.getOpt()) ? null : cl.getOptionValue(scanOptAuths.getOpt());
+    shellState.getConnector().securityOperations().changeUserAuthorizations(user, ScanCommand.parseAuthorizations(scanOpts));
+    Shell.log.debug("Changed record-level authorizations for user " + user);
+    return 0;
+  }
+  
+  @Override
+  public String description() {
+    return "sets the maximum scan authorizations for a user";
+  }
+  
+  @Override
+  public void registerCompletion(final Token root, final Map<Command.CompletionSet,Set<String>> completionSet) {
+    registerCompletionForUsers(root, completionSet);
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options o = new Options();
+    final OptionGroup setOrClear = new OptionGroup();
+    scanOptAuths = new Option("s", "scan-authorizations", true, "scan authorizations to set");
+    scanOptAuths.setArgName("comma-separated-authorizations");
+    setOrClear.addOption(scanOptAuths);
+    clearOptAuths = new Option("c", "clear-authorizations", false, "clear the scan authorizations");
+    setOrClear.addOption(clearOptAuths);
+    setOrClear.setRequired(true);
+    o.addOptionGroup(setOrClear);
+    userOpt = new Option(Shell.userOption, "user", true, "user to operate on");
+    userOpt.setArgName("user");
+    o.addOption(userOpt);
+    return o;
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/SetGroupsCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/SetGroupsCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/SetGroupsCommand.java
new file mode 100644
index 0000000..157dbd2
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/SetGroupsCommand.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.util.shell.commands;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.apache.hadoop.io.Text;
+
+public class SetGroupsCommand extends Command {
+  @Override
+  public String description() {
+    return "sets the locality groups for a given table (for binary or commas, use Java API)";
+  }
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+    final String tableName = OptUtil.getTableOpt(cl, shellState);
+    
+    final HashMap<String,Set<Text>> groups = new HashMap<String,Set<Text>>();
+    
+    for (String arg : cl.getArgs()) {
+      final String sa[] = arg.split("=", 2);
+      if (sa.length < 2) {
+        throw new IllegalArgumentException("Missing '='");
+      }
+      final String group = sa[0];
+      final HashSet<Text> colFams = new HashSet<Text>();
+      
+      for (String family : sa[1].split(",")) {
+        colFams.add(new Text(family.getBytes(Shell.CHARSET)));
+      }
+      
+      groups.put(group, colFams);
+    }
+    
+    shellState.getConnector().tableOperations().setLocalityGroups(tableName, groups);
+    
+    return 0;
+  }
+  
+  @Override
+  public int numArgs() {
+    return Shell.NO_FIXED_ARG_LENGTH_CHECK;
+  }
+  
+  @Override
+  public String usage() {
+    return getName() + " <group>=<col fam>{,<col fam>}{ <group>=<col fam>{,<col fam>}}";
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options opts = new Options();
+    opts.addOption(OptUtil.tableOpt("table to fetch locality groups for"));
+    return opts;
+  }
+  
+}