Hadoop Ls命令添加显示条数限制參数

2023-10-26

前言

在hadoop的FsShell命令中,预计非常多人比較经常使用的就是hadoop fs -ls,-lsr,-cat等等这种与Linux系统中差点儿一致的文件系统相关的命令.可是细致想想,这里还是有一些些的不同的.首先,从规模的本身来看,单机版的文件系统,文件数目少,内容不多,而HDFS则是一个分布式系统,里面能容纳巨大数量的文件文件夹.因此在这个前提之下,你假设任意运行ls或lsr命令,有的时候会得到恐怖的数据条数的显示记录,有的时候我们不得不通过Ctrl+C的方式中止命令.所以对于未知文件夹的命令运行,能否够在ls命令中添加显示限制的參数呢,这样能够控制一下文件记录信息的数量.这就是本文的一个出发点.


Ls命令工作流程

要想加入參数,就要先理解眼下Ls命令工作的原理和过程.以下我从源码的层面进行简单的分析.首先这里有个结构关系:

Ls-->FsCommand-->Command

从左到右依次为孩子到父亲.所以Command类是最基础的类,命令行操作的运行入口就在这里.进入到Command.java方法中,你会看到有以下这种方法:

/**
   * Invokes the command handler.  The default behavior is to process options,
   * expand arguments, and then process each argument.
   * <pre>
   * run
   * |-> {@link #processOptions(LinkedList)}
   * \-> {@link #processRawArguments(LinkedList)}
   *      |-> {@link #expandArguments(LinkedList)}
   *      |   \-> {@link #expandArgument(String)}*
   *      \-> {@link #processArguments(LinkedList)}
   *          |-> {@link #processArgument(PathData)}*
   *          |   |-> {@link #processPathArgument(PathData)}
   *          |   \-> {@link #processPaths(PathData, PathData...)}
   *          |        \-> {@link #processPath(PathData)}*
   *          \-> {@link #processNonexistentPath(PathData)}
   * </pre>
   * Most commands will chose to implement just
   * {@link #processOptions(LinkedList)} and {@link #processPath(PathData)}
   * 
   * @param argv the list of command line arguments
   * @return the exit code for the command
   * @throws IllegalArgumentException if called with invalid arguments
   */
  public int run(String...argv) {
    LinkedList<String> args = new LinkedList<String>(Arrays.asList(argv));
    try {
      if (isDeprecated()) {
        displayWarning(
            "DEPRECATED: Please use '"+ getReplacementCommand() + "' instead.");
      }
      processOptions(args);
      processRawArguments(args);
    } catch (IOException e) {
      displayError(e);
    }
    
    return (numErrors == 0) ? exitCode : exitCodeForError();
  }

首先会进行參数的预处理,在这里会把參数中的一些參数给剥离出来,由于这是一个抽象方法,所以终于的实现类在Ls.java中,代码例如以下:

  @Override
  protected void processOptions(LinkedList<String> args)
  throws IOException {
    CommandFormat cf = new CommandFormat(0, Integer.MAX_VALUE, "d", "h", "R");
    cf.parse(args);
    dirRecurse = !cf.getOpt("d");
    setRecursive(cf.getOpt("R") && dirRecurse);
    humanReadable = cf.getOpt("h");
    if (args.isEmpty()) args.add(Path.CUR_DIR);
  }
把这些參数逐一取出,然后这些參数会从args列表中被移除,最后就会剩下详细的目标浏览文件或文件夹的參数.以下就会进入到这种方法中:

  /**
   * Allows commands that don't use paths to handle the raw arguments.
   * Default behavior is to expand the arguments via
   * {@link #expandArguments(LinkedList)} and pass the resulting list to
   * {@link #processArguments(LinkedList)} 
   * @param args the list of argument strings
   * @throws IOException
   */
  protected void processRawArguments(LinkedList<String> args)
  throws IOException {
    processArguments(expandArguments(args));
  }
然后在expandArguments中会做一层从文件字符串到PathData详细对象的转化

 /**
   *  Expands a list of arguments into {@link PathData} objects.  The default
   *  behavior is to call {@link #expandArgument(String)} on each element
   *  which by default globs the argument.  The loop catches IOExceptions,
   *  increments the error count, and displays the exception.
   * @param args strings to expand into {@link PathData} objects
   * @return list of all {@link PathData} objects the arguments
   * @throws IOException if anything goes wrong...
   */
  protected LinkedList<PathData> expandArguments(LinkedList<String> args)
  throws IOException {
    LinkedList<PathData> expandedArgs = new LinkedList<PathData>();
    for (String arg : args) {
      try {
        expandedArgs.addAll(expandArgument(arg));
      } catch (IOException e) { // other exceptions are probably nasty
        displayError(e);
      }
    }
    return expandedArgs;
  }
  /**
   * Expand the given argument into a list of {@link PathData} objects.
   * The default behavior is to expand globs.  Commands may override to
   * perform other expansions on an argument.
   * @param arg string pattern to expand
   * @return list of {@link PathData} objects
   * @throws IOException if anything goes wrong...
   */
  protected List<PathData> expandArgument(String arg) throws IOException {
    PathData[] items = PathData.expandAsGlob(arg, getConf());
    if (items.length == 0) {
      // it's a glob that failed to match
      throw new PathNotFoundException(arg);
    }
    return Arrays.asList(items);
  }
最后以最后的PathData列表的信息来到终于的processArgument方法

/**
   *  Processes the command's list of expanded arguments.
   *  {@link #processArgument(PathData)} will be invoked with each item
   *  in the list.  The loop catches IOExceptions, increments the error
   *  count, and displays the exception.
   *  @param args a list of {@link PathData} to process
   *  @throws IOException if anything goes wrong... 
   */
  protected void processArguments(LinkedList<PathData> args)
  throws IOException {
    for (PathData arg : args) {
      try {
        processArgument(arg);
      } catch (IOException e) {
        displayError(e);
      }
    }
  }
然后对每一个pathData信息运行处理操作

  /**
   * Processes a {@link PathData} item, calling
   * {@link #processPathArgument(PathData)} or
   * {@link #processNonexistentPath(PathData)} on each item.
   * @param item {@link PathData} item to process
   * @throws IOException if anything goes wrong...
   */
  protected void processArgument(PathData item) throws IOException {
    if (item.exists) {
      processPathArgument(item);
    } else {
      processNonexistentPath(item);
    }
  }
然后运行Ls.java中的processPathArgument方法

  @Override
  protected void processPathArgument(PathData item) throws IOException {
    // implicitly recurse once for cmdline directories
    if (dirRecurse && item.stat.isDirectory()) {
      recursePath(item);
    } else {
      super.processPathArgument(item);
    }
  }
在这里会进程是否为文件夹的推断,假设是文件夹则会进行递归推断一次,进行子文件夹文件的展示.我们直接看是单文件的处理,基础方法在Comman.java中定义.

  /**
   *  This is the last chance to modify an argument before going into the
   *  (possibly) recursive {@link #processPaths(PathData, PathData...)}
   *  -> {@link #processPath(PathData)} loop.  Ex.  ls and du use this to
   *  expand out directories.
   *  @param item a {@link PathData} representing a path which exists
   *  @throws IOException if anything goes wrong... 
   */
  protected void processPathArgument(PathData item) throws IOException {
    // null indicates that the call is not via recursion, ie. there is
    // no parent directory that was expanded
    depth = 0;
    processPaths(null, item);
  }
然后processPaths又是在子类中详细实现

  @Override
  protected void processPaths(PathData parent, PathData ... items)
  throws IOException {
    if (parent != null && !isRecursive() && items.length != 0) {
      out.println("Found " + items.length + " items");
    }
    adjustColumnWidths(items);
    super.processPaths(parent, items);
  }
然后再次进行一个相似这种来回,运行processPaths方法

  /**
   *  Iterates over the given expanded paths and invokes
   *  {@link #processPath(PathData)} on each element.  If "recursive" is true,
   *  will do a post-visit DFS on directories.
   *  @param parent if called via a recurse, will be the parent dir, else null
   *  @param items a list of {@link PathData} objects to process
   *  @throws IOException if anything goes wrong...
   */
  protected void processPaths(PathData parent, PathData ... items)
  throws IOException {
    // TODO: this really should be iterative
    for (PathData item : items) {
      try {
        processPath(item);
        if (recursive && isPathRecursable(item)) {
          recursePath(item);
        }
        postProcessPath(item);
      } catch (IOException e) {
        displayError(e);
      }
    }
  }
最后展示的操作就是在这种方法中进行的

@Override
  protected void processPath(PathData item) throws IOException {
    FileStatus stat = item.stat;
    String line = String.format(lineFormat,
        (stat.isDirectory() ? "d" : "-"),
        stat.getPermission() + (stat.getPermission().getAclBit() ?

"+" : " "), (stat.isFile() ?

stat.getReplication() : "-"), stat.getOwner(), stat.getGroup(), formatSize(stat.getLen()), dateFormat.format(new Date(stat.getModificationTime())), item ); out.println(line); }

到这里整个ls调用的流程就基本结束了,预计有些读者要被这来回的方法绕晕了,只是没有关系,我们主要知道终于控制文件显示的方法在哪里,稍稍改改就能够达到我们的目的.


Ls限制显示參数的加入

如今我来教大家怎样新增ls命令參数.首先定义參数说明

public static final String NAME = "ls";
   public static final String USAGE = "[-d] [-h] [-R] [-l] [<path> ...]";
   public static final String DESCRIPTION =
 		    "List the contents that match the specified file pattern. If " +
 		    "path is not specified, the contents of /user/<currentUser> " +
@@ -53,7 +55,9 @@ public static void registerCommands(CommandFactory factory) {
 		    "-d:  Directories are listed as plain files.\n" +
 		    "-h:  Formats the sizes of files in a human-readable fashion " +
 		    "rather than a number of bytes.\n" +=
		    "-R:  Recursively list the contents of directories.\n" +
		    "-l:  The limited number of files records's info which would be " +
		    "displayed, the max value is 1024.\n";

定义相关变量

 
   protected int maxRepl = 3, maxLen = 10, maxOwner = 0, maxGroup = 0;
   protected int limitedDisplayedNum = 1024;
   protected int displayedRecordNum = 0;
   protected String lineFormat;
   protected boolean dirRecurse;
 
   protected boolean limitedDisplay = false;
   protected boolean humanReadable = false;
默认最大显示数目1024个.然后在參数解析的方法中进行新增參数的解析

   @Override
   protected void processOptions(LinkedList<String> args)
   throws IOException {
     CommandFormat cf = new CommandFormat(0, Integer.MAX_VALUE, "d", "h", "R", "l");
     cf.parse(args);
     dirRecurse = !cf.getOpt("d");
     setRecursive(cf.getOpt("R") && dirRecurse);
     humanReadable = cf.getOpt("h");
     limitedDisplay = cf.getOpt("l");
     if (args.isEmpty()) args.add(Path.CUR_DIR);
   }
然后是最核心的修改,processPaths方法

protected void processPaths(PathData parent, PathData ... items)
     if (parent != null && !isRecursive() && items.length != 0) {
       out.println("Found " + items.length   " items");
     }

     PathData[] newItems;
     if (limitedDisplay) {
       int length = items.length;
        if (length > limitedDisplayedNum) {
          length = limitedDisplayedNum;
          out.println("Found " + items.length + " items"
              + ", more than the limited displayed num " + limitedDisplayedNum);
        }
        newItems = new PathData[length];
  
        for (int i = 0; i < length; i++) {
          newItems[i] = items[i];
        }
        items = null;
      } else {
        newItems = items;
      }
  
      adjustColumnWidths(newItems);
      super.processPaths(parent, newItems);
   }

逻辑不难. 以下是測试的一个样例,我在測试的jar包中设置了默认限制数目1个,然后用ls命令分别測试带參数与不带參数的情况,測试截图例如以下:


此部分代码已经提交至开源社区,编号HADOOP-12641.链接在文章尾部列出.


相关链接

Issue链接:https://issues.apache.org/jira/browse/HADOOP-12641

github patch链接:https://github.com/linyiqun/open-source-patch/blob/master/hadoop/HADOOP-12641/HADOOP-12641.001.patch



转载于:https://www.cnblogs.com/mfmdaoyou/p/7403511.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Hadoop Ls命令添加显示条数限制參数 的相关文章

随机推荐

  • echo source 命令与 setup.bash与.bashrc文件

    编译完毕后键 echo source catkin ws devel setup bash gt gt bashrc source bashrc 本文分析这两条命令 echo 与source 以及setup bash文件与 bashrc两个
  • Flutter 布局Row(水平方向布局)、Column(垂直方向布局)、Wrap(可以自动换行的布局)、Flex(弹性布局)、Stack(叠层布局)、

    1 线性布局 Row 水平方向布局 Row 表示水平方向子组件的布局顺序 是从左往右还是从右往左 默认为系统当前Locale环境的文本方向 如中文 英语都是从左往右 而阿拉伯语是从右往左 TextDirection textDirectio
  • 通过模拟退火改进的Elman神经网络(Matlab代码实现)

    目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 1 概述 神经网络是一个庞大的体系和概念 根据处理信息的不同方式来区分不同的network 比如根据处理信息结果的传递方向 分前馈型与反馈型 前馈型网络会根据输出数值来调整网
  • dede php调用指定文章,DedeCMS调用指定文章内容的两种实现方法

    有时候我们需要dedecms能够调用指定文章的内容 尤其是在建企业网站的时候 需要在首页调用网站简介联系我们什么的 今天 织梦技术研究中心就给大家介绍两种实现调用指定文章内容的方法 方法一 打开include inc arcpart vie
  • Golang基础 函数详解 函数基础

    文章目录 01 函数声明 02 更多样的参数列表 03 更灵活的返回值列表 参考资料 函数是一个固定的 可重复使用的程序段 子程序 它在实现单一或相关联功能的同时 还可以带有入口和出口 所谓的入口 就是函数参数即形参 通过这个入口把函数的参
  • 最强 Verilog 中 IP核 调用实现及思想

    写在前面 无论是在 ISE 还是 Vivado 中 关于 IP核 的调用都是非常方便的 所以对于初学者来说最关键的不是在 IP Catalog 中设置相关的 IP核 参数 而是在生成相关的 IP核 后该怎么做 也即如何让这些 IP核 为项目
  • 海思3516系列芯片SPI速率慢问题深入研究与优化(基于PL022 SPI 控制器)

    海思3516系列芯片SPI速率慢问题深入分析与优化 基于PL022 SPI 控制器 我在某个海思主控的项目中需要使用SPI接口来驱动一块液晶屏 液晶屏主控为 st7789 分辨率 240x240 图像格式 RGB565 查阅海思相关手册可知
  • HDU - 1598之为达目的不择手段(并查集的应用)

    find the most comfortable road Time Limit 1000 1000 MS Java Others Memory Limit 32768 32768 K Java Others Total Submissi
  • docker快速搭建redis集群(两种暴露宿主网络的方法)

    宿主机IP 192 168 123 181 方案一 host网络模式 1 新建6个容器节点 for port in seq 4001 4006 do docker run itd name redis port network host v
  • Java线程:volatile关键字

    本文转载至 http lavasoft blog 51cto com 62575 222076 Java线程 volatile关键字 Java 语言包含两种内在的同步机制 同步块 或方法 和 volatile 变量 这两种机制的提出都是为了
  • 自制个人图床

    如何自制个人图床 有时候我们想要将自己的图片以链接的形式展示 就得需要使用图床 或者上传到自己的服务器 别人的图床会担心图片链接过期 然而自己的服务器会占用内存资源 所以我们就自制个人图床 首先你得有服务器和域名 好了废话不多说直接上教程
  • 2021-10-21

    当打开一个页面 需要第一行显示当前用户能够领取奖励的按钮 应用场景 1 当某些游戏有在线领奖的活动 比如在线10分钟 20分钟 以此类推可以领取一些奖励 当有很多时 页面装不下的时候 我们希望显示的第一个就是玩家可以领取的奖励 比如10分钟
  • C++—类和对象

    文章目录 1 类 2 对象 2 1 创建对象 2 2 对象的操作 2 3 构造函数 2 4 析构函数 3 静态成员 4 this指针 5 友元 一切我们研究的事物 都可以叫做对象 对象具有状态 操作和行为 通常用一个数值来描述对象的状态 对
  • DVWA ----Buete Force

    DVWA Buete Force 暴力破解 low 直接使用Burip suite来进行暴力破解 medium 与low的方法一样 但是在破解速度上比较慢 因为在源代码中多了sleep 函数 high 同样使用Burip suite进行暴力
  • RK3588开发板上使用Qt+OpenCV捕获摄像头图像

    在Qt下没有专门的视频采集与播放工具 这里使用了OpenCV所带的库函数捕获摄像头的视频图像 硬件环境 讯为RK3588开发板 OV5695 MIPI接口 摄像头 软件版本 OS ubuntu20 04镜像固件 QT 5 12 8 Qt C
  • 安全运营场景下的语言模型应用

    接上篇 将安全运营的定义为 使用算法能力提取关键信息 以此来规避算法误判漏判带来的责任问题 同时提升运营人员的工作效率 在这篇尝试对语言模型的使用方法做一下讨论和分享 1 语言模型 先聊一下语言模型 这里刻意规避了 大模型 这个词 主要是对
  • 【Python】循环语句

    目录 1 while 循环 2 for 循环 3 continue 4 break 1 while 循环 基本语法格式 while 条件 循环体 条件为真 则执行循环体代码 条件为假 则结束循环 例1 打印 1 10 的整数 num 1 w
  • pyspark合并两个dataframe_PySpark源码解析,教你用Python调用高效Scala接口

    在数据科学领域 Python 一直占据比较重要的地位 仍然有大量的数据工程师在使用各类 Python 数据处理和科学计算的库 例如 numpy Pandas scikit learn 等 相较于Scala语言而言 Python具有其独有的优
  • Mybatis 快速入门之mybatis与spring集成

    目录 一 基本概念撰述 1 SqlSessionFactory对象 只有创建了SqlSessionFactory对象 才能调用openSession 方法得到SqlSession对象 2 dao接口的代理对象 例如StudentDao接口
  • Hadoop Ls命令添加显示条数限制參数

    前言 在hadoop的FsShell命令中 预计非常多人比較经常使用的就是hadoop fs ls lsr cat等等这种与Linux系统中差点儿一致的文件系统相关的命令 可是细致想想 这里还是有一些些的不同的 首先 从规模的本身来看 单机