# Apache HBase Shell

> 贡献者：[xixici](https://github.com/xixici)

Apache HBase Shell 是 [(J)Ruby](http://jruby.org)'s IRB 的基础上增加了一些 HBase 特定的命令。你可以在 IRB 中做的任何事情，都可以在 HBase Shell 中完成。

要运行 HBase shell，请执行如下操作：


```
$ ./bin/hbase shell
```

输入：`help`，然后按 `<RETURN>` 查看 shell 命令和选项的列表。至少浏览器帮助输出末尾的段落，了解如何将变量和命令参数输入到 HBase shell 中；尤其要注意表名、行和列等是如何引用的。

请参阅 [shell exercises](#shell_exercises)。

这是 Rajeshbabu Chintaguntla 的[所有 shell 命令](http://learnhbase.wordpress.com/2013/03/02/hbase-shell-commands/)。

## 14\. 用 Ruby 编写脚本

有关 Apache HBase 脚本示例, 请查看 HBase _bin_ 文件夹. 查看以 _*.rb_ 结尾的文件. 执行下面操作,运行:

```
$ ./bin/hbase org.jruby.Main PATH_TO_SCRIPT
```

## 15\. 非交互方式运行 Shell

 HBase Shell 先增了一种非交互方式([HBASE-11658)](https://issues.apache.org/jira/browse/HBASE-11658).非交互模式捕获 HBase Shell 命令的退出状态（成功或失败），并将该状态返回给命令解释器。如果您使用正常的交互模式，HBase Shell 将只会返回自己的退出状态，这几乎总是会`0`成功的。

要调用非交互模式，请将 `-n` 或 `--non-interactive` 选项传递给 HBase Shell。


## 16\. 系统脚本中的 HBase Shell

您可以在操作系统脚本解释器中使用 HBase shell，例如 Bash shell，它是大多数 Linux 和 UNIX 发行版的默认命令解释程序。以下准则使用 Bash 语法，但可以调整为使用 C 样式的 shell（例如 csh 或 tcsh），并且可能会修改为使用 Microsoft Windows 脚本解释器一起使用。


> 这种方式生成 HBase Shell 命令的速度很慢，所以在决定何时将 HBase 操作与操作系统命令行相结合时，请记住这一点。

Example 4\. 传递命令到 HBase Shell

您可以使用 `echo` 命令和 `|`（管道）操作，以非交互模式将命令传递到 HBase Shell。 (详见: [hbase.shell.noninteractive](#hbase.shell.noninteractive)) .一定要转义 HBase 命令中的字符，否则 shell 将会解释这些字符。一些调试级别的输出已从下面的示例中截断。

```
$ echo "describe 'test1'" | ./hbase shell -n

Version 0.98.3-hadoop2, rd5e65a9144e315bb0a964e7730871af32f5018d5, Sat May 31 19:56:09 PDT 2014

describe 'test1'

DESCRIPTION                                          ENABLED
 'test1', {NAME => 'cf', DATA_BLOCK_ENCODING => 'NON true
 E', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0',
  VERSIONS => '1', COMPRESSION => 'NONE', MIN_VERSIO
 NS => '0', TTL => 'FOREVER', KEEP_DELETED_CELLS =>
 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false'
 , BLOCKCACHE => 'true'}
1 row(s) in 3.2410 seconds
```

若要取消所有输出，请将其回显到 /dev/null：

```
$ echo "describe 'test'" | ./hbase shell -n > /dev/null 2>&1
```

Example 5\. 检查脚本命令的结果

由于脚本不是设计为交互式运行的，因此您需要一种方法来检查命令是失败还是成功。HBase shell 使用为成功的命令返回值`0`的标准约定，并为失败的命令返回一些非零值。Bash 将命令的返回值存储在一个名为 `$?` 的特殊环境变量中。因为每次 shell 运行任何命令时都会覆盖该变量，所以应该将结果存储在另一个脚本定义的变量中。

下面的这个脚本展示了一种方法来存储返回值并根据它做出决定：


```
#!/bin/bash

echo "describe 'test'" | ./hbase shell -n > /dev/null 2>&1
status=$?
echo "The status was " $status
if ($status == 0); then
    echo "The command succeeded"
else
    echo "The command may have failed."
fi
return $status
```

### 16.1\. 在脚本中检查成功或失败


获取退出代码`0`意味着您脚本编写的命令确实成功了。但是，获取非零退出代码并不一定意味着命令失败。该命令可能已成功，但客户端失去连接，或者其他事件阻碍了其成功。这是因为 RPC 命令是无状态的。确保操作状态的唯一方法是检查。例如，如果你的脚本创建一个表，但返回一个非零的退出值，你应该检查表是否实际创建，然后再试图创建它。


## 17\. 从命令文件读取 HBase Shell 命令


您可以将 HBase Shell 命令输入到文本文件中，每行一个命令，并将该文件传递给 HBase Shell。


命令文件示例

```
create 'test', 'cf'
list 'test'
put 'test', 'row1', 'cf:a', 'value1'
put 'test', 'row2', 'cf:b', 'value2'
put 'test', 'row3', 'cf:c', 'value3'
put 'test', 'row4', 'cf:d', 'value4'
scan 'test'
get 'test', 'row1'
disable 'test'
enable 'test'
```

Example 6\. 指示 HBase Shell 执行命令

将命令文件的路径作为 `hbase shell` 命令的唯一参数传递。每个命令都会执行并显示其输出。如果您未在脚本中包含该 `exit` 命令，则会返回到 HBase shell 提示符。没有办法以编程方式检查每个单独的命令是否成功或失败。此外，尽管您看到每个命令的输出，但命令本身并未回显到屏幕，因此可能难以将命令与其输出对齐。


```
$ ./hbase shell ./sample_commands.txt
0 row(s) in 3.4170 seconds

TABLE
test
1 row(s) in 0.0590 seconds

0 row(s) in 0.1540 seconds

0 row(s) in 0.0080 seconds

0 row(s) in 0.0060 seconds

0 row(s) in 0.0060 seconds

ROW                   COLUMN+CELL
 row1                 column=cf:a, timestamp=1407130286968, value=value1
 row2                 column=cf:b, timestamp=1407130286997, value=value2
 row3                 column=cf:c, timestamp=1407130287007, value=value3
 row4                 column=cf:d, timestamp=1407130287015, value=value4
4 row(s) in 0.0420 seconds

COLUMN                CELL
 cf:a                 timestamp=1407130286968, value=value1
1 row(s) in 0.0110 seconds

0 row(s) in 1.5630 seconds

0 row(s) in 0.4360 seconds
```

## 18\. 将 VM 选项传递给 Shell

您可以使用 `HBASE_SHELL_OPTS` 环境变量将 VM 选项传递到 HBase Shell 。您可以在您的环境中进行设置，例如通过编辑 _〜/.bashrc_，或将其设置为启动 HBase Shell 的命令的一部分。以下的示例设置了几个与垃圾回收相关的变量，仅用于运行 HBase Shell 的 VM 的生命周期。为了可读性，该命令应该在单行中全部运行，但是会被 `\` 字符打断。


```
$ HBASE_SHELL_OPTS="-verbose:gc -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps \
  -XX:+PrintGCDetails -Xloggc:$HBASE_HOME/logs/gc-hbase.log" ./bin/hbase shell
```

## 19\. 覆盖启动 HBase Shell 的配置

hbase-2.0.5/hbase-2.1.3/hbase-2.2.0/hbase-1.4.10/hbase-1.5.0, 您可以传递或覆盖`hbase-*.xml`中指定的 hbase 配置。在命令行上传递前缀为`-D`的键/值，如下所示：

```
$ ./bin/hbase shell -Dhbase.zookeeper.quorum=ZK0.remote.cluster.example.org,ZK1.remote.cluster.example.org,ZK2.remote.cluster.example.org -Draining=false
...
hbase(main):001:0> @shell.hbase.configuration.get("hbase.zookeeper.quorum")
=> "ZK0.remote.cluster.example.org,ZK1.remote.cluster.example.org,ZK2.remote.cluster.example.org"
hbase(main):002:0> @shell.hbase.configuration.get("raining")
=> "false"

```

## 20\. Shell 技巧

### 20.1\. Table 变量

HBase 0.95 版本增加了为表提供 jruby 风格的面向对象引用的 shell 命令。以前，作用于表的所有 shell 命令都具有程序风格，该风格始终将表的名称作为参数。HBase 0.95 引入了将表分配给 jruby 变量的功能。表引用可以用来执行数据读写操作，比如放入、扫描、以及管理功能（如禁用，删除，描述表等）。


例如，以前你总是会指定一个表名：


```
hbase(main):000:0> create 't', 'f'
0 row(s) in 1.0970 seconds
hbase(main):001:0> put 't', 'rold', 'f', 'v'
0 row(s) in 0.0080 seconds

hbase(main):002:0> scan 't'
ROW                                COLUMN+CELL
 rold                              column=f:, timestamp=1378473207660, value=v
1 row(s) in 0.0130 seconds

hbase(main):003:0> describe 't'
DESCRIPTION                                                                           ENABLED
 't', {NAME => 'f', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_ true
 SCOPE => '0', VERSIONS => '1', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2
 147483647', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false
 ', BLOCKCACHE => 'true'}
1 row(s) in 1.4430 seconds

hbase(main):004:0> disable 't'
0 row(s) in 14.8700 seconds

hbase(main):005:0> drop 't'
0 row(s) in 23.1670 seconds

hbase(main):006:0>

```

现在，您可以将该表分配给一个变量，并在 jruby shell 代码中使用结果。


```
hbase(main):007 > t = create 't', 'f'
0 row(s) in 1.0970 seconds

=> Hbase::Table - t
hbase(main):008 > t.put 'r', 'f', 'v'
0 row(s) in 0.0640 seconds
hbase(main):009 > t.scan
ROW                           COLUMN+CELL
 r                            column=f:, timestamp=1331865816290, value=v
1 row(s) in 0.0110 seconds
hbase(main):010:0> t.describe
DESCRIPTION                                                                           ENABLED
 't', {NAME => 'f', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_ true
 SCOPE => '0', VERSIONS => '1', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2
 147483647', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false
 ', BLOCKCACHE => 'true'}
1 row(s) in 0.0210 seconds
hbase(main):038:0> t.disable
0 row(s) in 6.2350 seconds
hbase(main):039:0> t.drop
0 row(s) in 0.2340 seconds

```

如果该表已被创建，则可以使用 get_table 方法将一个表分配给一个变量：


```
hbase(main):011 > create 't','f'
0 row(s) in 1.2500 seconds

=> Hbase::Table - t
hbase(main):012:0> tab = get_table 't'
0 row(s) in 0.0010 seconds

=> Hbase::Table - t
hbase(main):013:0> tab.put 'r1' ,'f', 'v'
0 row(s) in 0.0100 seconds
hbase(main):014:0> tab.scan
ROW                                COLUMN+CELL
 r1                                column=f:, timestamp=1378473876949, value=v
1 row(s) in 0.0240 seconds
hbase(main):015:0>

```

列表功能也已被扩展，以便它返回一个表名称作为字符串的列表。然后，您可以使用 jruby 根据这些名称对表操作进行脚本编写。list_snapshots 命令的作用也相似。


```
hbase(main):016 > tables = list('t.*')
TABLE
t
1 row(s) in 0.1040 seconds

=> #<#<Class:0x7677ce29>:0x21d377a4>
hbase(main):017:0> tables.map { |t| disable t ; drop  t}
0 row(s) in 2.2510 seconds

=> [nil]
hbase(main):018:0>

```

### 20.2\. _irbrc_

在您的主目录中为自己创建一个 _.irbrc_ 文件，添加自定义项。一个有用的是历史记录命令，因此命令可以跨 Shell 调用进行保存：

```
$ more .irbrc
require 'irb/ext/save-history'
IRB.conf[:SAVE_HISTORY] = 100
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-save-history"

```

如果您想避免将每个表达式的计算结果打印到 stderr，例如从“list”命令返回的表数组：


```
$ echo "IRB.conf[:ECHO] = false" >>~/.irbrc

```

请参阅 _.irbrc_ 的`ruby`文档以了解其他可能的配置。

### 20.3\. LOG data to timestamp


要将日期'08/08/16 20:56:29'从 hbase 日志转换为时间戳，请执行以下操作：

```
hbase(main):021:0> import java.text.SimpleDateFormat
hbase(main):022:0> import java.text.ParsePosition
hbase(main):023:0> SimpleDateFormat.new("yy/MM/dd HH:mm:ss").parse("08/08/16 20:56:29", ParsePosition.new(0)).getTime() => 1218920189000

```

相反

```
hbase(main):021:0> import java.util.Date
hbase(main):022:0> Date.new(1218920189000).toString() => "Sat Aug 16 20:56:29 UTC 2008"

```

以与 HBase 日志格式完全相同的格式输出将会对[SimpleDateFormat](http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html) 产生一些影响。



### 20.4\. 查询 Shell 配置


```
hbase(main):001:0> @shell.hbase.configuration.get("hbase.rpc.timeout")
=> "60000"

```

在 shell 中设置一个配置：


```
hbase(main):005:0> @shell.hbase.configuration.setInt("hbase.rpc.timeout", 61010)
hbase(main):006:0> @shell.hbase.configuration.get("hbase.rpc.timeout")
=> "61010"

```

### 20.5\. 使用 HBase Shell 预分割表


在通过 HBase Shell 的 `create` 命令创建表时，您可以使用各种选项预先拆分表。


最简单的方法是在创建表格时指定一个分割点数组。请注意，当将字符串文字指定为分割点时，这些将根据字符串的基础字节表示创建分割点。所以当指定分割点“10”时，我们实际上是指定了字节分割点“\x31\30”。


分割点将定义 `n+1 ` 区域，其中 `n` 是分割点的数量。最低的区域将包含从最低可能的键直到但不包括第一分割点密钥的所有密钥。下一个区域将包含从第一个分割点开始的密钥，但不包括下一个分割点密钥键。这将持续到最后的所有分界点。最后一个区域将从最后一个拆分点定义为最大可能的密钥。


```
hbase>create 't1','f',SPLITS => ['10','20','30']

```

在上面的例子中，将使用列族 "f" 创建表 "t1"，预先拆分到四个区域。请注意，第一个区域将包含从“\x00”到“\x30”（因为“\x31”是“1”的 ASCII 码）的所有密钥。


您可以使用以下变化将分割点传递到文件中。在这个例子中，分割是从对应于本地文件系统上的本地路径的文件中读取的。文件中的每一行都指定一个分割点密钥。


```
hbase>create 't14','f',SPLITS_FILE=>'splits.txt'

```

其他选项是根据所需的区域数量和分割算法自动计算分割。HBase 提供基于统一拆分或基于十六进制密钥分割密钥范围的算法，但您可以提供自己的拆分算法来细分密钥范围。


```
# 根据随机字节键创建包含四个区域的表
hbase>create 't2','f1', { NUMREGIONS => 4 , SPLITALGO => 'UniformSplit' }

# 基于十六进制键创建具有五个区域的表
hbase>create 't3','f1', { NUMREGIONS => 5, SPLITALGO => 'HexStringSplit' }

```

由于 HBase Shell 实际上是一个 Ruby 环境，因此您可以使用简单的 Ruby 脚本以算法方式计算分割。


```
# generate splits for long (Ruby fixnum) key range from start to end key
hbase(main):070:0> def gen_splits(start_key,end_key,num_regions)
hbase(main):071:1>   results=[]
hbase(main):072:1>   range=end_key-start_key
hbase(main):073:1>   incr=(range/num_regions).floor
hbase(main):074:1>   for i in 1 .. num_regions-1
hbase(main):075:2>     results.push([i*incr+start_key].pack("N"))
hbase(main):076:2>   end
hbase(main):077:1>   return results
hbase(main):078:1> end
hbase(main):079:0>
hbase(main):080:0> splits=gen_splits(1,2000000,10)
=> ["\000\003\r@", "\000\006\032\177", "\000\t'\276", "\000\f4\375", "\000\017B<", "\000\022O{", "\000\025\\\272", "\000\030i\371", "\000\ew8"]
hbase(main):081:0> create 'test_splits','f',SPLITS=>splits
0 row(s) in 0.2670 seconds

=> Hbase::Table - test_splits

```

请注意，HBase Shell 命令 `truncate` 有效地删除并重新创建具有默认选项的表格，这将丢弃任何预分割。如果您需要截断预分割表，则必须显式删除并重新创建表以重新指定自定义分割选项。


### 20.6\. 调试

#### 20.6.1\. Shell 调试开关

您可以在 shell 中设置一个调试开关，以查看更多输出 - 例如，运行命令时出现更多的异常堆栈跟踪：


```
hbase> debug <RETURN>

```

#### 20.6.2\. DEBUG log level

要在 shell 中启用 DEBUG 级日志记录，请使用该 `-d` 选项启动它：


```
$ ./bin/hbase shell -d

```

### 20.7\. 命令

#### 20.7.1\. count

Count 命令返回表中的行数。配置正确的 CACHE 时速度非常快：


```
hbase> count '<tablename>', CACHE => 1000

```

上述计数一次取 1000 行。如果行很大，请将 CACHE 设置得较低。默认是每次读取一行。