【问题标题】:Unix: Sort 'ls' by return value of programUnix:按程序的返回值对“ls”进行排序
【发布时间】:2020-09-02 05:37:50
【问题描述】:

如何在 Unix shell 中使用程序作为键来排序?换句话说,通过每行应用的程序的返回值对“ls”(或任何其他程序)的输出进行排序。

【问题讨论】:

  • 这个问题(按手动定义的顺序排序)非常有趣。但是,它现在的制定方式可能会导致很多形式为“don't parse ls”、“XY problem”、“needs more details 的 cmets。我建议编辑问题以关注 "sort by a manually defined order" (此命令可以来自ls,但不是必须的)。然后,给出更多细节,例如,当元素不按自定义顺序时应该如何排序?
  • 并详细介绍该计划。是像 compare string1 string2 返回 -1、0 或 1 还是一个完整的排序程序(像 sort)?在最后一种情况下,您可以使用 ls | mysortingprogram 之类的东西。
  • 我想按 i-node 编号对文件列表进行排序。该程序采用文件名并返回 inode。我必须为此使用这个程序(这是一个家庭作业)。
  • ls -i1 |种类。 'ls -i1' 显示每个文件的 inode 和 1 col 的输出,而 'sort' 确实是排序

标签: linux bash unix scripting


【解决方案1】:

我将给出两个示例解决方案:

  1. 一个更简单的单行命令,因此我会先尝试使用它。

  2. 一个 bash 脚本,允许通过读取列表的每一行作为输入的任意 bash 函数的输出对列表进行排序。

示例1(每行不执行命令)

如果问题是一般情况下如何对ls 等程序的输出进行排序,下面是一个特定于ls 的示例,它按inode 排序。但是,每个程序在生成其输出时都可能有自己的特点,因此可能需要修改此示例:

ls -ail /home/user/ | tail -n+2 | tr -s ' ' | sort -t' ' -k1,1 -g

以下是此命令的不同部分:

ls -ail /home/user/

使用 inode (-i) 以列表 (-l) 格式列出目录 /home/user/ 中的所有 (-a) 文件。

tail -n+1

从 ls 输出中截断第一行。

tr -s ' '

sort 组合 (-s) 多个空格 (' ')。

sort -t ' ' -k 1 -g

按由一个空格 (' ') 分隔的整数 (-g) 的第一个 (1) 字段对列表进行排序。

示例2(以每一行为输入执行命令)

这是我编写的 bash 脚本中的一个更具适应性的示例,用于展示如何将 ls -a1 生成的文件列表输入 bash 函数 getinode,该函数使用 stat 输出每个文件的 inode。 while 循环对每个文件重复此过程,通过重复附加名为 OUTPUT 的变量以逗号分隔格式保存数据,该变量最后使用第一个字段按 sort 排序。

重要的部分是函数getinode可以是任何东西,只要它输出一个字符串。我设置getinode 接收文件路径作为输入(第一个参数$1),然后通过echo $INODE 将inode 输出到stdout。脚本通过$(getinode "$FILEPATH")调用getinode

#!/bin/bash

# Usage: lsinodesort.sh [file]
# Refs/attrib:
#   [1]: How to sort a csv file by sorting on a single field. https://stackoverflow.com/a/44744800
#   [2]: How to read a while loop variable. https://stackoverflow.com/a/16854326

WORKDIR="$1" # read directory from first argument

getinode() {
    # Usage: getinode [path]
    INODE="$(stat "$1" --format=%i)"
    echo $INODE
}

if [ -d "$WORKDIR" ]; then
    LINES="$(ls -a1 "$WORKDIR")" # save `ls` output to variable LINES
else
    exit 1; # not a valid directory
fi

while read line; do
    path="$WORKDIR"/"$line" # Determine path.
    if [ -f "$path" ]; then # Check if path is a file.
    FILEPATH="$path"
    FILENAME="$(basename "$path")" # Determine filename from path.
    FILEINODE=$(getinode "$FILEPATH") # Get inode.
    OUTPUT="$FILEINODE"",""$FILENAME""\n""$OUTPUT" ; # Append inode and file name to OUTPUT
    fi
done <<< "$LINES"  # See [2].

OUTPUT=$(printf "${OUTPUT}" | sort -t, -k1,1) # sort OUTPUT. See [1]
OUTPUT="inode","filename""\n""$OUTPUT"
printf "${OUTPUT}\n" # print final OUTPUT.

当我在自己的主文件夹上运行它时,我会得到如下输出:

inode,filename
3932162,.bashrc
3932165,.bash_logout
3932382,.zshrc
3932454,.gitconfig
3933234,.bash_aliases
3933512,.profile
3933612,.viminfo

【讨论】:

    【解决方案2】:

    我不确定你的问题是否理解,所以我会先尝试重新措辞。 如果我没记错的话,您想对程序的输出进行排序(它可能是 ls 或 Unix shell 中的任何其他命令)。 我建议使用 Unix shell 上可用的管道功能。 例如,您可以使用以下命令对 ls 命令的输出进行排序:

    ls /home | sort
    

    此功能可用但不限于 ls 命令。 顺便说一句,如果这是您的特定用例,您可以使用可选标志对 ls 命令结果进行排序:

    ls -S # for sorting by file size
    ls -t # for sorting by modification time
    

    您还可以附加--reverse-r 标志以反向显示结果。

    至于sort 函数,还有一些标志允许根据您的需要自定义结果:

    sort -n # for sorting numerically instead of alphabetically
    sort -k5 # for sorting based on the 5th column
    sort -t "," # for using the comma as a field separator
    

    您可以像这样组合所有这些,以便根据字段 2,5(数字)和 9(非数字/字母顺序)对“ls -l”命令的输出进行排序。

    ls -l /home/$USER | sort -t "," -nk2,5 -k9 
    

    sort function examples

    【讨论】:

      猜你喜欢
      • 2010-10-27
      • 1970-01-01
      • 2018-08-14
      • 2011-12-11
      • 2017-09-30
      • 1970-01-01
      • 2018-09-15
      • 2017-07-08
      • 1970-01-01
      相关资源
      最近更新 更多