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:01 UTC

[05/53] [abbrv] ACCUMULO-1897 Move shell into new package and module

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteNamespaceCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteNamespaceCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteNamespaceCommand.java
new file mode 100644
index 0000000..faf1147
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteNamespaceCommand.java
@@ -0,0 +1,100 @@
+/*
+ * 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.shell.commands;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.accumulo.core.client.NamespaceNotFoundException;
+import org.apache.accumulo.core.client.impl.Namespaces;
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.Token;
+import org.apache.accumulo.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class DeleteNamespaceCommand extends Command {
+  private Option forceOpt;
+
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+    boolean force = false;
+    boolean operate = true;
+    if (cl.hasOption(forceOpt.getOpt())) {
+      force = true;
+    }
+    String namespace = cl.getArgs()[0];
+
+    if (!force) {
+      shellState.getReader().flush();
+      String line = shellState.getReader().readLine(getName() + " { " + namespace + " } (yes|no)? ");
+      operate = line != null && (line.equalsIgnoreCase("y") || line.equalsIgnoreCase("yes"));
+    }
+    if (operate) {
+      doTableOp(shellState, namespace, force);
+    }
+    return 0;
+  }
+
+  @Override
+  public String description() {
+    return "deletes a namespace";
+  }
+
+  protected void doTableOp(final Shell shellState, final String namespace, boolean force) throws Exception {
+    boolean resetContext = false;
+    String currentTable = shellState.getTableName();
+    if (!Namespaces.getNameToIdMap(shellState.getInstance()).containsKey(namespace)) {
+      throw new NamespaceNotFoundException(null, namespace, null);
+    }
+
+    String namespaceId = Namespaces.getNamespaceId(shellState.getInstance(), namespace);
+    List<String> tables = Namespaces.getTableNames(shellState.getInstance(), namespaceId);
+    resetContext = tables.contains(currentTable);
+
+    if (force)
+      for (String table : shellState.getConnector().tableOperations().list())
+        if (table.startsWith(namespace + "."))
+          shellState.getConnector().tableOperations().delete(table);
+
+    shellState.getConnector().namespaceOperations().delete(namespace);
+    if (resetContext) {
+      shellState.setTableName("");
+    }
+  }
+
+  @Override
+  public Options getOptions() {
+    forceOpt = new Option("f", "force", false, "force deletion without prompting");
+    final Options opts = super.getOptions();
+
+    opts.addOption(forceOpt);
+    return opts;
+  }
+
+  @Override
+  public int numArgs() {
+    return 1;
+  }
+
+  @Override
+  public void registerCompletion(final Token root, final Map<Command.CompletionSet,Set<String>> special) {
+    registerCompletionForNamespaces(root, special);
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteRowsCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteRowsCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteRowsCommand.java
new file mode 100644
index 0000000..09f2938
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteRowsCommand.java
@@ -0,0 +1,65 @@
+/*
+ * 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.shell.commands;
+
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.Shell.Command;
+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 DeleteRowsCommand extends Command {
+  private Option forceOpt;
+  private Option startRowOptExclusive;
+ 
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+    final String tableName = OptUtil.getTableOpt(cl, shellState);
+    final Text startRow = OptUtil.getStartRow(cl);
+    final Text endRow = OptUtil.getEndRow(cl);
+    if (!cl.hasOption(forceOpt.getOpt()) && (startRow == null || endRow == null)) {
+      shellState.getReader().println("Not deleting unbounded range. Specify both ends, or use --force");
+      return 1;
+    }
+    shellState.getConnector().tableOperations().deleteRows(tableName, startRow, endRow);
+    return 0;
+  }
+  
+  @Override
+  public String description() {
+    return "deletes a range of rows in a table.  Note that rows matching the start row ARE NOT deleted, but rows matching the end row ARE deleted.";
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options o = new Options();
+    forceOpt = new Option("f", "force", false, "delete data even if start or end are not specified");
+    startRowOptExclusive = new Option(OptUtil.START_ROW_OPT, "begin-row", true, "begin row (exclusive)");
+    startRowOptExclusive.setArgName("begin-row");
+    o.addOption(startRowOptExclusive);
+    o.addOption(OptUtil.endRowOpt());
+    o.addOption(OptUtil.tableOpt("table to delete a row range from"));
+    o.addOption(forceOpt);
+    return o;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteScanIterCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteScanIterCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteScanIterCommand.java
new file mode 100644
index 0000000..f3c9823
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteScanIterCommand.java
@@ -0,0 +1,102 @@
+/*
+ * 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.shell.commands;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.accumulo.core.client.IteratorSetting;
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.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 DeleteScanIterCommand extends Command {
+  private Option nameOpt, allOpt;
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+    final String tableName = OptUtil.getTableOpt(cl, shellState);
+    
+    if (cl.hasOption(allOpt.getOpt())) {
+      final List<IteratorSetting> tableScanIterators = shellState.scanIteratorOptions.remove(tableName);
+      if (tableScanIterators == null) {
+        Shell.log.info("No scan iterators set on table " + tableName);
+      } else {
+        Shell.log.info("Removed the following scan iterators from table " + tableName + ":" + tableScanIterators);
+      }
+    } else if (cl.hasOption(nameOpt.getOpt())) {
+      final String name = cl.getOptionValue(nameOpt.getOpt());
+      final List<IteratorSetting> tableScanIterators = shellState.scanIteratorOptions.get(tableName);
+      if (tableScanIterators != null) {
+        boolean found = false;
+        for (Iterator<IteratorSetting> iter = tableScanIterators.iterator(); iter.hasNext();) {
+          if (iter.next().getName().equals(name)) {
+            iter.remove();
+            found = true;
+            break;
+          }
+        }
+        if (!found) {
+          Shell.log.info("No iterator named " + name + " found for table " + tableName);
+        } else {
+          Shell.log.info("Removed scan iterator " + name + " from table " + tableName + " (" + shellState.scanIteratorOptions.get(tableName).size() + " left)");
+          if (shellState.scanIteratorOptions.get(tableName).size() == 0) {
+            shellState.scanIteratorOptions.remove(tableName);
+          }
+        }
+      } else {
+        Shell.log.info("No iterator named " + name + " found for table " + tableName);
+      }
+    }
+    
+    return 0;
+  }
+  
+  @Override
+  public String description() {
+    return "deletes a table-specific scan iterator so it is no longer used during this shell session";
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options o = new Options();
+    
+    OptionGroup nameGroup = new OptionGroup();
+    
+    nameOpt = new Option("n", "name", true, "iterator to delete");
+    nameOpt.setArgName("itername");
+    
+    allOpt = new Option("a", "all", false, "delete all scan iterators");
+    allOpt.setArgName("all");
+    
+    nameGroup.addOption(nameOpt);
+    nameGroup.addOption(allOpt);
+    nameGroup.setRequired(true);
+    o.addOptionGroup(nameGroup);
+    o.addOption(OptUtil.tableOpt("table to delete scan iterators from"));
+    
+    return o;
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteShellIterCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteShellIterCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteShellIterCommand.java
new file mode 100644
index 0000000..3010f0b
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteShellIterCommand.java
@@ -0,0 +1,100 @@
+/*
+ * 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.shell.commands;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.accumulo.core.client.IteratorSetting;
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.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 DeleteShellIterCommand extends Command {
+  private Option nameOpt, allOpt, profileOpt;
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+
+    String profile = cl.getOptionValue(profileOpt.getOpt());
+    if (shellState.iteratorProfiles.containsKey(profile)) {
+      if (cl.hasOption(allOpt.getOpt())) {
+        shellState.iteratorProfiles.remove(profile);
+        Shell.log.info("Removed profile " + profile);
+      } else {
+        List<IteratorSetting> iterSettings = shellState.iteratorProfiles.get(profile);
+        String name = cl.getOptionValue(nameOpt.getOpt());
+        boolean found = false;
+        for (Iterator<IteratorSetting> iter = iterSettings.iterator(); iter.hasNext();) {
+          if (iter.next().getName().equals(name)) {
+            iter.remove();
+            found = true;
+            break;
+          }
+        }
+        if (!found) {
+          Shell.log.info("No iterator named " + name + " found");
+        } else {
+          Shell.log.info("Removed iterator " + name + " from profile " + profile + " (" + iterSettings.size() + " left)");
+        }
+      }
+      
+    } else {
+      Shell.log.info("No profile named " + profile);
+    }
+    
+    return 0;
+  }
+  
+  @Override
+  public String description() {
+    return "deletes iterators profiles configured in this shell session";
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options o = new Options();
+    
+    OptionGroup nameGroup = new OptionGroup();
+    
+    nameOpt = new Option("n", "name", true, "iterator to delete");
+    nameOpt.setArgName("itername");
+    
+    allOpt = new Option("a", "all", false, "delete all scan iterators");
+    allOpt.setArgName("all");
+    
+    nameGroup.addOption(nameOpt);
+    nameGroup.addOption(allOpt);
+    nameGroup.setRequired(true);
+    o.addOptionGroup(nameGroup);
+    
+    profileOpt = new Option("pn", "profile", true, "iterator profile name");
+    profileOpt.setRequired(true);
+    profileOpt.setArgName("profile");
+    o.addOption(profileOpt);
+
+    return o;
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteTableCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteTableCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteTableCommand.java
new file mode 100644
index 0000000..827a8ec
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteTableCommand.java
@@ -0,0 +1,60 @@
+/*
+ * 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.shell.commands;
+
+import org.apache.accumulo.shell.Shell;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class DeleteTableCommand extends TableOperation {
+  private Option forceOpt;
+
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+    if (cl.hasOption(forceOpt.getOpt())) {
+      super.force();
+    } else {
+      super.noForce();
+    }
+    return super.execute(fullCommand, cl, shellState);
+  }
+
+  @Override
+  public String description() {
+    return "deletes a table";
+  }
+
+  @Override
+  protected void doTableOp(final Shell shellState, final String tableName) throws Exception {
+    shellState.getConnector().tableOperations().delete(tableName);
+    shellState.getReader().println("Table: [" + tableName + "] has been deleted.");
+
+    if (shellState.getTableName().equals(tableName)) {
+      shellState.setTableName("");
+    }
+  }
+
+  @Override
+  public Options getOptions() {
+    forceOpt = new Option("f", "force", false, "force deletion without prompting");
+    final Options opts = super.getOptions();
+
+    opts.addOption(forceOpt);
+    return opts;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteUserCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteUserCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteUserCommand.java
new file mode 100644
index 0000000..22d072a
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteUserCommand.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.shell.commands;
+
+public class DeleteUserCommand extends DropUserCommand {}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/DropTableCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/DropTableCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/DropTableCommand.java
new file mode 100644
index 0000000..45b40dd
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/DropTableCommand.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.shell.commands;
+
+public class DropTableCommand extends DeleteTableCommand {}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/DropUserCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/DropUserCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/DropUserCommand.java
new file mode 100644
index 0000000..7de216d
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/DropUserCommand.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.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.BadArgumentException;
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.Token;
+import org.apache.accumulo.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+
+public class DropUserCommand extends Command {
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException {
+    final String user = cl.getArgs()[0];
+    if (shellState.getConnector().whoami().equals(user)) {
+      throw new BadArgumentException("You cannot delete yourself", fullCommand, fullCommand.indexOf(user));
+    }
+    shellState.getConnector().securityOperations().dropLocalUser(user);
+    Shell.log.debug("Deleted user " + user);
+    return 0;
+  }
+  
+  @Override
+  public String description() {
+    return "deletes a user";
+  }
+  
+  @Override
+  public String usage() {
+    return getName() + " <username>";
+  }
+  
+  @Override
+  public void registerCompletion(final Token root, final Map<Command.CompletionSet,Set<String>> completionSet) {
+    registerCompletionForUsers(root, completionSet);
+  }
+  
+  @Override
+  public int numArgs() {
+    return 1;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/EGrepCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/EGrepCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/EGrepCommand.java
new file mode 100644
index 0000000..958f5eb
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/EGrepCommand.java
@@ -0,0 +1,59 @@
+/*
+ * 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.shell.commands;
+
+import java.io.IOException;
+
+import org.apache.accumulo.core.client.BatchScanner;
+import org.apache.accumulo.core.client.IteratorSetting;
+import org.apache.accumulo.core.iterators.user.RegExFilter;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class EGrepCommand extends GrepCommand {
+  
+  private Option matchSubstringOption;
+  
+  @Override
+  protected void setUpIterator(final int prio, final String name, final String term, final BatchScanner scanner, CommandLine cl) throws IOException {
+    if (prio < 0) {
+      throw new IllegalArgumentException("Priority < 0 " + prio);
+    }
+    final IteratorSetting si = new IteratorSetting(prio, name, RegExFilter.class);
+    RegExFilter.setRegexs(si, term, term, term, term, true, cl.hasOption(matchSubstringOption.getOpt()));
+    scanner.addScanIterator(si);
+  }
+  
+  @Override
+  public String description() {
+    return "searches each row, column family, column qualifier and value, in parallel, on the server side (using a java Matcher, so put .* before and after your term if you're not matching the whole element)";
+  }
+  
+  @Override
+  public String usage() {
+    return getName() + " <regex>{ <regex>}";
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options opts = super.getOptions();
+    matchSubstringOption = new Option("g", "global", false, "forces the use of the find() expression matcher, causing substring matches to return true");
+    opts.addOption(matchSubstringOption);
+    return opts;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/ExecfileCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/ExecfileCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/ExecfileCommand.java
new file mode 100644
index 0000000..b384d5c
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/ExecfileCommand.java
@@ -0,0 +1,67 @@
+/*
+ * 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.shell.commands;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.util.Scanner;
+
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class ExecfileCommand extends Command {
+  private Option verboseOption;
+  
+  @Override
+  public String description() {
+    return "specifies a file containing accumulo commands to execute";
+  }
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+    Scanner scanner = new Scanner(new File(cl.getArgs()[0]), StandardCharsets.UTF_8.name());
+    try {
+      while (scanner.hasNextLine()) {
+        shellState.execCommand(scanner.nextLine(), true, cl.hasOption(verboseOption.getOpt()));
+      }
+    } finally {
+      scanner.close();
+    }
+    return 0;
+  }
+  
+  @Override
+  public String usage() {
+    return getName() + " <fileName>";
+  }
+  
+  @Override
+  public int numArgs() {
+    return 1;
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options opts = new Options();
+    verboseOption = new Option("v", "verbose", false, "display command prompt as commands are executed");
+    opts.addOption(verboseOption);
+    return opts;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/ExitCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/ExitCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/ExitCommand.java
new file mode 100644
index 0000000..1d44409
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/ExitCommand.java
@@ -0,0 +1,39 @@
+/*
+ * 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.shell.commands;
+
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+
+public class ExitCommand extends Command {
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) {
+    shellState.setExit(true);
+    return 0;
+  }
+  
+  @Override
+  public String description() {
+    return "exits the shell";
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/ExportTableCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/ExportTableCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/ExportTableCommand.java
new file mode 100644
index 0000000..d8d358c
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/ExportTableCommand.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.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.shell.Shell;
+import org.apache.accumulo.shell.Token;
+import org.apache.accumulo.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class ExportTableCommand extends Command {
+  
+  private Option tableOpt;
+
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException, TableNotFoundException,
+      TableExistsException {
+    
+    final String tableName = OptUtil.getTableOpt(cl, shellState);
+
+    shellState.getConnector().tableOperations().exportTable(tableName, cl.getArgs()[0]);
+    return 0;
+  }
+  
+  @Override
+  public String usage() {
+    return getName() + " <export dir>";
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options o = new Options();
+    
+    tableOpt = new Option(Shell.tableOption, "table", true, "table to export");
+    
+    tableOpt.setArgName("table");
+    
+    o.addOption(tableOpt);
+
+    return o;
+  }
+  
+  @Override
+  public String description() {
+    return "exports a table";
+  }
+  
+  public void registerCompletion(final Token root, final Map<Command.CompletionSet,Set<String>> completionSet) {
+    registerCompletionForTables(root, completionSet);
+  }
+  
+  @Override
+  public int numArgs() {
+    return 1;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/ExtensionCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/ExtensionCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/ExtensionCommand.java
new file mode 100644
index 0000000..fbc1833
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/ExtensionCommand.java
@@ -0,0 +1,102 @@
+/*
+ * 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.shell.commands;
+
+import java.util.HashSet;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.ShellExtension;
+import org.apache.accumulo.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class ExtensionCommand extends Command {
+  
+  protected Option enable, disable, list;
+  
+  private static ServiceLoader<ShellExtension> extensions = null;
+  
+  private Set<String> loadedHeaders = new HashSet<String>();
+  private Set<String> loadedCommands = new HashSet<String>();
+  private Set<String> loadedExtensions = new TreeSet<String>();
+  
+  public int execute(String fullCommand, CommandLine cl, Shell shellState) throws Exception {
+    if (cl.hasOption(enable.getOpt())) {
+      extensions = ServiceLoader.load(ShellExtension.class);
+      for (ShellExtension se : extensions) {
+        
+        loadedExtensions.add(se.getExtensionName());
+        String header = "-- " + se.getExtensionName() + " Extension Commands ---------";
+        loadedHeaders.add(header);
+        shellState.commandGrouping.put(header, se.getCommands());
+        
+        for (Command cmd : se.getCommands()) {
+          String name = se.getExtensionName() + "::" + cmd.getName();
+          loadedCommands.add(name);
+          shellState.commandFactory.put(name, cmd);
+        }
+      }
+    } else if (cl.hasOption(disable.getOpt())) {
+      //Remove the headers
+      for (String header : loadedHeaders) {
+        shellState.commandGrouping.remove(header);
+      }
+      //remove the commands
+      for (String name : loadedCommands) {
+        shellState.commandFactory.remove(name);
+      }
+      //Reset state
+      loadedExtensions.clear();
+      extensions.reload();
+    } else if (cl.hasOption(list.getOpt())) {
+      shellState.printLines(loadedExtensions.iterator(), true);
+    } else {
+      printHelp(shellState);
+    }
+    return 0;
+  }
+  
+  public String description() {
+    return "Enable, disable, or list shell extensions";
+  }
+  
+  public int numArgs() {
+    return 0;
+  }
+  
+  @Override
+  public String getName() {
+    return "extensions";
+  }
+
+  @Override
+  public Options getOptions() {
+    final Options o = new Options();
+    enable = new Option("e", "enable", false, "enable shell extensions");
+    disable = new Option("d", "disable", false, "disable shell extensions");
+    list = new Option("l", "list", false, "list shell extensions");
+    o.addOption(enable);
+    o.addOption(disable);
+    o.addOption(list);
+    return o;
+  }
+    
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/FateCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/FateCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/FateCommand.java
new file mode 100644
index 0000000..eae1ec8
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/FateCommand.java
@@ -0,0 +1,180 @@
+/*
+ * 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.shell.commands;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Formatter;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.zookeeper.ZooUtil;
+import org.apache.accumulo.fate.AdminUtil;
+import org.apache.accumulo.fate.ReadOnlyTStore.TStatus;
+import org.apache.accumulo.fate.ZooStore;
+import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
+import org.apache.accumulo.fate.zookeeper.ZooReaderWriter;
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.zookeeper.KeeperException;
+
+/**
+ * Manage FATE transactions
+ * 
+ */
+public class FateCommand extends Command {
+  
+  private static final String SCHEME = "digest";
+  
+  private static final String USER = "accumulo";
+  
+  private Option secretOption;
+  private Option statusOption;
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws ParseException, KeeperException, InterruptedException,
+      IOException {
+    Instance instance = shellState.getInstance();
+    String[] args = cl.getArgs();
+    if (args.length <= 0) {
+      throw new ParseException("Must provide a command to execute");
+    }
+    String cmd = args[0];
+    boolean failedCommand = false;
+    
+    AdminUtil<FateCommand> admin = new AdminUtil<FateCommand>(false);
+    
+    String path = ZooUtil.getRoot(instance) + Constants.ZFATE;
+    String masterPath = ZooUtil.getRoot(instance) + Constants.ZMASTER_LOCK;
+    IZooReaderWriter zk = getZooReaderWriter(shellState.getInstance(), cl.getOptionValue(secretOption.getOpt()));
+    ZooStore<FateCommand> zs = new ZooStore<FateCommand>(path, zk);
+    
+    if ("fail".equals(cmd)) {
+      if (args.length <= 1) {
+        throw new ParseException("Must provide transaction ID");
+      }
+      for (int i = 1; i < args.length; i++) {
+        if (!admin.prepFail(zs, zk, masterPath, args[i])) {
+          System.out.printf("Could not fail transaction: %s%n", args[i]);
+          failedCommand = true;
+        }
+      }
+    } else if ("delete".equals(cmd)) {
+      if (args.length <= 1) {
+        throw new ParseException("Must provide transaction ID");
+      }
+      for (int i = 1; i < args.length; i++) {
+        if (admin.prepDelete(zs, zk, masterPath, args[i])) {
+          admin.deleteLocks(zs, zk, ZooUtil.getRoot(instance) + Constants.ZTABLE_LOCKS, args[i]);
+        } else {
+          System.out.printf("Could not delete transaction: %s%n", args[i]);
+          failedCommand = true;
+        }
+      }
+    } else if ("list".equals(cmd) || "print".equals(cmd)) {
+      // Parse transaction ID filters for print display
+      Set<Long> filterTxid = null;
+      if (args.length >= 2) {
+        filterTxid = new HashSet<Long>(args.length);
+        for (int i = 1; i < args.length; i++) {
+          try {
+            Long val = Long.parseLong(args[i], 16);
+            filterTxid.add(val);
+          } catch (NumberFormatException nfe) {
+            // Failed to parse, will exit instead of displaying everything since the intention was to potentially filter some data
+            System.out.printf("Invalid transaction ID format: %s%n", args[i]);
+            return 1;
+          }
+        }
+      }
+      
+      // Parse TStatus filters for print display
+      EnumSet<TStatus> filterStatus = null;
+      if (cl.hasOption(statusOption.getOpt())) {
+        filterStatus = EnumSet.noneOf(TStatus.class);
+        String[] tstat = cl.getOptionValues(statusOption.getOpt());
+        for (int i = 0; i < tstat.length; i++) {
+          try {
+            filterStatus.add(TStatus.valueOf(tstat[i]));
+          } catch (IllegalArgumentException iae) {
+            System.out.printf("Invalid transaction status name: %s%n", tstat[i]);
+            return 1;
+          }
+        }
+      }
+      
+      StringBuilder buf = new StringBuilder(8096);
+      Formatter fmt = new Formatter(buf);
+      admin.print(zs, zk, ZooUtil.getRoot(instance) + Constants.ZTABLE_LOCKS, fmt, filterTxid, filterStatus);
+      shellState.printLines(Collections.singletonList(buf.toString()).iterator(), true);
+    } else {
+      throw new ParseException("Invalid command option");
+    }
+    
+    return failedCommand ? 1 : 0;
+  }
+  
+  protected synchronized IZooReaderWriter getZooReaderWriter(Instance instance, String secret) {
+    
+    if (secret == null) {
+      @SuppressWarnings("deprecation")
+      AccumuloConfiguration conf = AccumuloConfiguration.getSiteConfiguration();
+      secret = conf.get(Property.INSTANCE_SECRET);
+    }
+    
+    return new ZooReaderWriter(instance.getZooKeepers(), instance.getZooKeepersSessionTimeOut(), SCHEME, (USER + ":" + secret).getBytes());
+  }
+  
+  @Override
+  public String description() {
+    return "manage FATE transactions";
+  }
+  
+  @Override
+  public String usage() {
+    return getName() + " fail <txid>... | delete <txid>... | print [<txid>...]";
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options o = new Options();
+    secretOption = new Option("s", "secret", true, "specify the instance secret to use");
+    secretOption.setOptionalArg(false);
+    o.addOption(secretOption);
+    statusOption = new Option("t", "status-type", true,
+        "filter 'print' on the transaction status type(s) {NEW, IN_PROGRESS, FAILED_IN_PROGRESS, FAILED, SUCCESSFUL}");
+    statusOption.setArgs(Option.UNLIMITED_VALUES);
+    statusOption.setOptionalArg(false);
+    o.addOption(statusOption);
+    return o;
+  }
+  
+  @Override
+  public int numArgs() {
+    // Arg length varies between 1 to n
+    return -1;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/FlushCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/FlushCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/FlushCommand.java
new file mode 100644
index 0000000..34e22a5
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/FlushCommand.java
@@ -0,0 +1,63 @@
+/*
+ * 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.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.shell.Shell;
+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 FlushCommand extends TableOperation {
+  private Text startRow;
+  private Text endRow;
+  
+  private boolean wait;
+  private Option waitOpt;
+  
+  @Override
+  public String description() {
+    return "flushes a tables data that is currently in memory to disk";
+  }
+  
+  protected void doTableOp(final Shell shellState, final String tableName) throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
+    shellState.getConnector().tableOperations().flush(tableName, startRow, endRow, wait);
+    Shell.log.info("Flush 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());
+    startRow = OptUtil.getStartRow(cl);
+    endRow = OptUtil.getEndRow(cl);
+    return super.execute(fullCommand, cl, shellState);
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options opts = super.getOptions();
+    waitOpt = new Option("w", "wait", false, "wait for flush to finish");
+    opts.addOption(waitOpt);
+    opts.addOption(OptUtil.startRowOpt());
+    opts.addOption(OptUtil.endRowOpt());
+    
+    return opts;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/FormatterCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/FormatterCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/FormatterCommand.java
new file mode 100644
index 0000000..e416699
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/FormatterCommand.java
@@ -0,0 +1,69 @@
+/*
+ * 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.shell.commands;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.util.format.Formatter;
+import org.apache.accumulo.shell.Shell;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class FormatterCommand extends ShellPluginConfigurationCommand {
+  
+  private Option interpeterOption;
+
+  public FormatterCommand() {
+    super("formatter", Property.TABLE_FORMATTER_CLASS, "f");
+  }
+
+  @Override
+  public String description() {
+    return "specifies a formatter to use for displaying table entries";
+  }
+
+  public static Class<? extends Formatter> getCurrentFormatter(final String tableName, final Shell shellState) {
+    return ShellPluginConfigurationCommand.getPluginClass(tableName, shellState, Formatter.class, Property.TABLE_FORMATTER_CLASS);
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options options = super.getOptions();
+    
+    interpeterOption = new Option("i", "interpeter", false, "configure class as interpreter also");
+    
+    options.addOption(interpeterOption);
+    
+    return options;
+  }
+  
+  protected void setPlugin(final CommandLine cl, final Shell shellState, final String tableName, final String className) throws AccumuloException, AccumuloSecurityException {
+    super.setPlugin(cl, shellState, tableName, className);
+    if (cl.hasOption(interpeterOption.getOpt())) {
+      shellState.getConnector().tableOperations().setProperty(tableName, Property.TABLE_INTERPRETER_CLASS.toString(), className);
+    }
+  }
+  
+  protected void removePlugin(final CommandLine cl, final Shell shellState, final String tableName) throws AccumuloException, AccumuloSecurityException {
+    super.removePlugin(cl, shellState, tableName);
+    if (cl.hasOption(interpeterOption.getOpt())) {
+      shellState.getConnector().tableOperations().removeProperty(tableName, Property.TABLE_INTERPRETER_CLASS.toString());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/GetAuthsCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/GetAuthsCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/GetAuthsCommand.java
new file mode 100644
index 0000000..0156d44
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/GetAuthsCommand.java
@@ -0,0 +1,67 @@
+/*
+ * 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.shell.commands;
+
+import java.io.IOException;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.lang.StringUtils;
+
+public class GetAuthsCommand extends Command {
+  private Option userOpt;
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException, IOException {
+    final String user = cl.getOptionValue(userOpt.getOpt(), shellState.getConnector().whoami());
+    // Sort authorizations
+    Authorizations auths = shellState.getConnector().securityOperations().getUserAuthorizations(user);
+    SortedSet<String> set = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+    for (byte[] auth : auths) {
+      set.add(new String(auth));
+    }
+    shellState.getReader().println(StringUtils.join(set, ','));
+    return 0;
+  }
+  
+  @Override
+  public String description() {
+    return "displays the maximum scan authorizations for a user";
+  }
+  
+  @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/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/GetGroupsCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/GetGroupsCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/GetGroupsCommand.java
new file mode 100644
index 0000000..6cae7e0
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/GetGroupsCommand.java
@@ -0,0 +1,60 @@
+/*
+ * 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.shell.commands;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.accumulo.core.util.LocalityGroupUtil;
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.apache.hadoop.io.Text;
+
+public class GetGroupsCommand extends Command {
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+    final String tableName = OptUtil.getTableOpt(cl, shellState);
+    
+    final Map<String,Set<Text>> groups = shellState.getConnector().tableOperations().getLocalityGroups(tableName);
+    
+    for (Entry<String,Set<Text>> entry : groups.entrySet()) {
+      shellState.getReader().println(entry.getKey() + "=" + LocalityGroupUtil.encodeColumnFamilies(entry.getValue()));
+    }
+    return 0;
+  }
+  
+  @Override
+  public String description() {
+    return "gets the locality groups for a given table";
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options opts = new Options();
+    opts.addOption(OptUtil.tableOpt("table to fetch locality groups from"));
+    return opts;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/GetSplitsCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/GetSplitsCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/GetSplitsCommand.java
new file mode 100644
index 0000000..f275c39
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/GetSplitsCommand.java
@@ -0,0 +1,155 @@
+/*
+ * 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.shell.commands;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Iterator;
+import java.util.Map.Entry;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.Scanner;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.KeyExtent;
+import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.Value;
+import org.apache.accumulo.core.metadata.MetadataTable;
+import org.apache.accumulo.core.metadata.RootTable;
+import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.util.TextUtil;
+import org.apache.accumulo.core.util.format.BinaryFormatter;
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.Shell.Command;
+import org.apache.accumulo.shell.Shell.PrintFile;
+import org.apache.accumulo.shell.Shell.PrintLine;
+import org.apache.accumulo.shell.Shell.PrintShell;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.hadoop.io.Text;
+
+public class GetSplitsCommand extends Command {
+  
+  private Option outputFileOpt, maxSplitsOpt, base64Opt, verboseOpt;
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws IOException, AccumuloException, AccumuloSecurityException,
+      TableNotFoundException {
+    final String tableName = OptUtil.getTableOpt(cl, shellState);
+    
+    final String outputFile = cl.getOptionValue(outputFileOpt.getOpt());
+    final String m = cl.getOptionValue(maxSplitsOpt.getOpt());
+    final int maxSplits = m == null ? 0 : Integer.parseInt(m);
+    final boolean encode = cl.hasOption(base64Opt.getOpt());
+    final boolean verbose = cl.hasOption(verboseOpt.getOpt());
+    
+    final PrintLine p = outputFile == null ? new PrintShell(shellState.getReader()) : new PrintFile(outputFile);
+    
+    try {
+      if (!verbose) {
+        for (Text row : maxSplits > 0 ? shellState.getConnector().tableOperations().listSplits(tableName, maxSplits) : shellState.getConnector()
+            .tableOperations().listSplits(tableName)) {
+          p.print(encode(encode, row));
+        }
+      } else {
+        String systemTableToCheck = MetadataTable.NAME.equals(tableName) ? RootTable.NAME : MetadataTable.NAME;
+        final Scanner scanner = shellState.getConnector().createScanner(systemTableToCheck, Authorizations.EMPTY);
+        TabletsSection.TabletColumnFamily.PREV_ROW_COLUMN.fetch(scanner);
+        final Text start = new Text(shellState.getConnector().tableOperations().tableIdMap().get(tableName));
+        final Text end = new Text(start);
+        end.append(new byte[] {'<'}, 0, 1);
+        scanner.setRange(new Range(start, end));
+        for (Iterator<Entry<Key,Value>> iterator = scanner.iterator(); iterator.hasNext();) {
+          final Entry<Key,Value> next = iterator.next();
+          if (TabletsSection.TabletColumnFamily.PREV_ROW_COLUMN.hasColumns(next.getKey())) {
+            KeyExtent extent = new KeyExtent(next.getKey().getRow(), next.getValue());
+            final String pr = encode(encode, extent.getPrevEndRow());
+            final String er = encode(encode, extent.getEndRow());
+            final String line = String.format("%-26s (%s, %s%s", obscuredTabletName(extent), pr == null ? "-inf" : pr, er == null ? "+inf" : er,
+                er == null ? ") Default Tablet " : "]");
+            p.print(line);
+          }
+        }
+      }
+      
+    } finally {
+      p.close();
+    }
+    
+    return 0;
+  }
+  
+  private static String encode(final boolean encode, final Text text) {
+    if (text == null) {
+      return null;
+    }
+    BinaryFormatter.getlength(text.getLength());
+    return encode ? new String(Base64.encodeBase64(TextUtil.getBytes(text)), StandardCharsets.UTF_8) : BinaryFormatter.appendText(new StringBuilder(), text).toString();
+  }
+  
+  private static String obscuredTabletName(final KeyExtent extent) {
+    MessageDigest digester;
+    try {
+      digester = MessageDigest.getInstance("MD5");
+    } catch (NoSuchAlgorithmException e) {
+      throw new RuntimeException(e);
+    }
+    if (extent.getEndRow() != null && extent.getEndRow().getLength() > 0) {
+      digester.update(extent.getEndRow().getBytes(), 0, extent.getEndRow().getLength());
+    }
+    return new String(Base64.encodeBase64(digester.digest()), StandardCharsets.UTF_8);
+  }
+  
+  @Override
+  public String description() {
+    return "retrieves the current split points for tablets in the current table";
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options opts = new Options();
+    
+    outputFileOpt = new Option("o", "output", true, "local file to write the splits to");
+    outputFileOpt.setArgName("file");
+    
+    maxSplitsOpt = new Option("m", "max", true, "maximum number of splits to return (evenly spaced)");
+    maxSplitsOpt.setArgName("num");
+    
+    base64Opt = new Option("b64", "base64encoded", false, "encode the split points");
+    
+    verboseOpt = new Option("v", "verbose", false, "print out the tablet information with start/end rows");
+    
+    opts.addOption(outputFileOpt);
+    opts.addOption(maxSplitsOpt);
+    opts.addOption(base64Opt);
+    opts.addOption(verboseOpt);
+    opts.addOption(OptUtil.tableOpt("table to get splits for"));
+    
+    return opts;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/GrantCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/GrantCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/GrantCommand.java
new file mode 100644
index 0000000..8f4448f
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/GrantCommand.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.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.shell.Shell;
+import org.apache.accumulo.shell.Token;
+import org.apache.accumulo.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 GrantCommand 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().grantSystemPermission(user, SystemPermission.valueOf(permission[1]));
+        Shell.log.debug("Granted " + 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()
+              .grantNamespacePermission(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().grantTablePermission(user, tableName, TablePermission.valueOf(permission[1]));
+      Shell.log.debug("Granted " + user + " the " + permission[1] + " permission on table " + tableName);
+    } catch (IllegalArgumentException e) {
+      throw new IllegalArgumentException("No such table permission", e);
+    }
+  }
+
+  @Override
+  public String description() {
+    return "grants system, table, or namespace permissions for 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, "grant 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/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/GrepCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/GrepCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/GrepCommand.java
new file mode 100644
index 0000000..1a3c484
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/GrepCommand.java
@@ -0,0 +1,111 @@
+/*
+ * 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.shell.commands;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.accumulo.core.client.BatchScanner;
+import org.apache.accumulo.core.client.IteratorSetting;
+import org.apache.accumulo.core.iterators.user.GrepIterator;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.util.format.Formatter;
+import org.apache.accumulo.core.util.interpret.ScanInterpreter;
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.Shell.PrintFile;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.MissingArgumentException;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class GrepCommand extends ScanCommand {
+  
+  private Option numThreadsOpt;
+  
+  @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);
+    
+    if (cl.getArgList().isEmpty()) {
+      throw new MissingArgumentException("No terms specified");
+    }
+    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
+    int numThreads = 20;
+    if (cl.hasOption(numThreadsOpt.getOpt())) {
+      numThreads = Integer.parseInt(cl.getOptionValue(numThreadsOpt.getOpt()));
+    }
+    final Authorizations auths = getAuths(cl, shellState);
+    final BatchScanner scanner = shellState.getConnector().createBatchScanner(tableName, auths, numThreads);
+    scanner.setRanges(Collections.singletonList(getRange(cl, interpeter)));
+    
+    scanner.setTimeout(getTimeout(cl), TimeUnit.MILLISECONDS);
+    
+    for (int i = 0; i < cl.getArgs().length; i++) {
+      setUpIterator(Integer.MAX_VALUE - cl.getArgs().length + i, "grep" + i, cl.getArgs()[i], scanner, cl);
+    }
+    try {
+      // handle columns
+      fetchColumns(cl, scanner, interpeter);
+      
+      // output the records
+      printRecords(cl, shellState, scanner, formatter, printFile);
+    } finally {
+      scanner.close();
+    }
+    
+    return 0;
+  }
+  
+  protected void setUpIterator(final int prio, final String name, final String term, final BatchScanner scanner, CommandLine cl) throws IOException {
+    if (prio < 0) {
+      throw new IllegalArgumentException("Priority < 0 " + prio);
+    }
+    final IteratorSetting grep = new IteratorSetting(prio, name, GrepIterator.class);
+    GrepIterator.setTerm(grep, term);
+    scanner.addScanIterator(grep);
+  }
+  
+  @Override
+  public String description() {
+    return "searches each row, column family, column qualifier and value in a table for a substring (not a regular expression), in parallel, on the server side";
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options opts = super.getOptions();
+    numThreadsOpt = new Option("nt", "num-threads", true, "number of threads to use");
+    opts.addOption(numThreadsOpt);
+    return opts;
+  }
+  
+  @Override
+  public String usage() {
+    return getName() + " <term>{ <term>}";
+  }
+  
+  @Override
+  public int numArgs() {
+    return Shell.NO_FIXED_ARG_LENGTH_CHECK;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/HelpCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/HelpCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/HelpCommand.java
new file mode 100644
index 0000000..90e8c4f
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/HelpCommand.java
@@ -0,0 +1,129 @@
+/*
+ * 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.shell.commands;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.ShellCommandException;
+import org.apache.accumulo.shell.Token;
+import org.apache.accumulo.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class HelpCommand extends Command {
+  private Option disablePaginationOpt;
+  private Option noWrapOpt;
+  
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws ShellCommandException, IOException {
+    int numColumns = shellState.getReader().getTerminal().getWidth();
+    if (cl.hasOption(noWrapOpt.getOpt())) {
+      numColumns = Integer.MAX_VALUE;
+    }
+    // print help summary
+    if (cl.getArgs().length == 0) {
+      int i = 0;
+      for (String cmd : shellState.commandFactory.keySet()) {
+        i = Math.max(i, cmd.length());
+      }
+      if (numColumns < 40) {
+        throw new IllegalArgumentException("numColumns must be at least 40 (was " + numColumns + ")");
+      }
+      final ArrayList<String> output = new ArrayList<String>();
+      for (Entry<String,Command[]> cmdGroup : shellState.commandGrouping.entrySet()) {
+        output.add(cmdGroup.getKey());
+        for (Command c : cmdGroup.getValue()) {
+          String n = c.getName();
+          String s = c.description();
+          if (s == null) {
+            s = "";
+          }
+          int beginIndex = 0;
+          int endIndex = s.length();
+          while (beginIndex < endIndex && s.charAt(beginIndex) == ' ')
+            beginIndex++;
+          String dash = "-";
+          while (endIndex > beginIndex && endIndex - beginIndex + i + 5 > numColumns) {
+            endIndex = s.lastIndexOf(" ", numColumns + beginIndex - i - 5);
+            if (endIndex == -1 || endIndex < beginIndex) {
+              endIndex = numColumns + beginIndex - i - 5 - 1;
+              output.add(String.format("%-" + i + "s  %s  %s-", n, dash, s.substring(beginIndex, endIndex)));
+              dash = " ";
+              beginIndex = endIndex;
+            } else {
+              output.add(String.format("%-" + i + "s  %s  %s", n, dash, s.substring(beginIndex, endIndex)));
+              dash = " ";
+              beginIndex = endIndex + 1;
+            }
+            n = "";
+            endIndex = s.length();
+            while (beginIndex < endIndex && s.charAt(beginIndex) == ' ') {
+              beginIndex++;
+            }
+          }
+          output.add(String.format("%-" + i + "s  %s  %s", n, dash, s.substring(beginIndex, endIndex)));
+        }
+        output.add("");
+      }
+      shellState.printLines(output.iterator(), !cl.hasOption(disablePaginationOpt.getOpt()));
+    }
+    
+    // print help for every command on command line
+    for (String cmd : cl.getArgs()) {
+      final Command c = shellState.commandFactory.get(cmd);
+      if (c == null) {
+        shellState.getReader().println(String.format("Unknown command \"%s\".  Enter \"help\" for a list possible commands.", cmd));
+      } else {
+        c.printHelp(shellState, numColumns);
+      }
+    }
+    return 0;
+  }
+  
+  public String description() {
+    return "provides information about the available commands";
+  }
+  
+  public void registerCompletion(final Token root, final Map<Command.CompletionSet,Set<String>> special) {
+    registerCompletionForCommands(root, special);
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options o = new Options();
+    disablePaginationOpt = new Option("np", "no-pagination", false, "disable pagination of output");
+    o.addOption(disablePaginationOpt);
+    noWrapOpt = new Option("nw", "no-wrap", false, "disable wrapping of output");
+    o.addOption(noWrapOpt);
+    return o;
+  }
+  
+  @Override
+  public String usage() {
+    return getName() + " [ <command>{ <command>} ]";
+  }
+  
+  @Override
+  public int numArgs() {
+    return Shell.NO_FIXED_ARG_LENGTH_CHECK;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/HiddenCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/HiddenCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/HiddenCommand.java
new file mode 100644
index 0000000..824517d
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/HiddenCommand.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.shell.commands;
+
+import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
+import java.util.Random;
+
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.ShellCommandException;
+import org.apache.accumulo.shell.Shell.Command;
+import org.apache.accumulo.shell.ShellCommandException.ErrorCode;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.codec.binary.Base64;
+
+public class HiddenCommand extends Command {
+  private static Random rand = new SecureRandom();
+  
+  @Override
+  public String description() {
+    return "The first rule of Accumulo is: \"You don't talk about Accumulo.\"";
+  }
+  
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+    if (rand.nextInt(10) == 0) {
+      shellState.getReader().beep();
+      shellState.getReader().println();
+      shellState.getReader().println(
+          new String(Base64.decodeBase64(("ICAgICAgIC4tLS4KICAgICAgLyAvXCBcCiAgICAgKCAvLS1cICkKICAgICAuPl8gIF88LgogICAgLyB8ICd8ICcgXAog"
+              + "ICAvICB8Xy58Xy4gIFwKICAvIC98ICAgICAgfFwgXAogfCB8IHwgfFwvfCB8IHwgfAogfF98IHwgfCAgfCB8IHxffAogICAgIC8gIF9fICBcCiAgICAvICAv"
+              + "ICBcICBcCiAgIC8gIC8gICAgXCAgXF8KIHwvICAvICAgICAgXCB8IHwKIHxfXy8gICAgICAgIFx8X3wK").getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8));
+    } else {
+      throw new ShellCommandException(ErrorCode.UNRECOGNIZED_COMMAND, getName());
+    }
+    return 0;
+  }
+  
+  @Override
+  public int numArgs() {
+    return Shell.NO_FIXED_ARG_LENGTH_CHECK;
+  }
+  
+  @Override
+  public String getName() {
+    return "accvmvlo";
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/bcc9e7e4/shell/src/main/java/org/apache/accumulo/shell/commands/HistoryCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/HistoryCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/HistoryCommand.java
new file mode 100644
index 0000000..1c1314a
--- /dev/null
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/HistoryCommand.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.shell.commands;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.ListIterator;
+
+import jline.console.history.History.Entry;
+
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.collections.iterators.AbstractIteratorDecorator;
+
+public class HistoryCommand extends Command {
+  private Option clearHist;
+  private Option disablePaginationOpt;
+  
+  @SuppressWarnings("unchecked")
+  @Override
+  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws IOException {
+    if (cl.hasOption(clearHist.getOpt())) {
+      shellState.getReader().getHistory().clear();
+    } else {
+      ListIterator<Entry> it = shellState.getReader().getHistory().entries();
+      shellState.printLines(new HistoryLineIterator(it), !cl.hasOption(disablePaginationOpt.getOpt()));
+    }
+    
+    return 0;
+  }
+  
+  /**
+   * Decorator that converts an Iterator<History.Entry> to an Iterator<String>.
+   */
+  private static class HistoryLineIterator extends AbstractIteratorDecorator {
+    public HistoryLineIterator(Iterator<Entry> iterator) {
+      super(iterator);
+    }
+    
+    @Override
+    public String next() {
+      return super.next().toString();
+    }
+  }
+  
+  @Override
+  public String description() {
+    return ("generates a list of commands previously executed");
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+  
+  @Override
+  public Options getOptions() {
+    final Options o = new Options();
+    clearHist = new Option("c", "clear", false, "clear history file");
+    o.addOption(clearHist);
+    disablePaginationOpt = new Option("np", "no-pagination", false, "disable pagination of output");
+    o.addOption(disablePaginationOpt);
+    return o;
+  }
+}