【问题标题】:(bash scripting) How to sort the lines that are in a position multiple of 'n' in a file?(bash脚本)如何对文件中'n'倍数的行进行排序?
【发布时间】:2017-07-08 06:50:53
【问题描述】:

我必须在 ubuntu linux 中用 bash 语言编写一个脚本,该脚本必须在命令行中接受三个参数:首先是我必须对其行进行排序的文件的名称,其次是一个字母(如果我想要,'a'如果我想按字母降序排序,则按字母升序或“z”排序),第三个是正数“n”。我只需要对“n”的倍数的行进行排序。例如,如果我有一个包含 100 行且 n=5 的文本文件,那么我必须只对第 5、10、15、...、100 行进行排序,其余的必须保持不变。这可以做到吗? 我可以像这样查找和排序是 'n' 的倍数的行:

awk "NR%$n==0" archivo.txt | sort -f 

但现在我不知道如何将这些行再次写入文件。

感谢关注

【问题讨论】:

  • 向我们展示你目前拥有的东西。
  • 我可以找到是 'n' 的倍数的行并像这样对它们进行排序: awk "NR%$n==0" file.txt | sort -f 但现在我无法再次将这些行重新引入文件中。
  • 仅供参考,最好写成awk -v n="$n" 'NR % n == 0';使用字符串替换来生成脚本(在任何语言中——不仅是 awk,还包括 bash、SQL 等)显然是不安全的,而不是从代码中带外传递数据。

标签: bash ubuntu scripting


【解决方案1】:

如果您不介意将整个输入文件放入内存,则可以使用 gawk,以便在打印之前对行子集进行排序。

#!/usr/bin/env gawk -f

BEGIN {
  if (!inc) inc=5              # set a default
}

NR%inc {
  # This is a normal line
  nosort[NR]=$0
  next
}

{
  # This is an increment of "inc"
  tosort[NR]=$0
}

END {
  # Sort the array of increments
  asort(tosort)

  # Step through our two arrays, picking what to print based on the modulo
  n=0
  for (i=1; i<NR; i++)
    if (i%inc==0)
      print tosort[++n]
    else
      print nosort[i]
}

你可以用类似这样的方式运行它:

$ ./sortthing -v inc=5 inputfile

请注意,这使用了 gawk 函数asort(),它在 One True Awk 中不存在。因此,如果您在 *BSD 或 OS X 上执行此操作,您可能需要安装其他工具。

【讨论】:

  • 非常感谢。
【解决方案2】:

毫无疑问,这也可以在纯 awk 中完成,但以下使用本机 bash:

#!/usr/bin/env bash

input=${1:-archivo.txt} # set input to $1, or default to archivo.txt
n=${2:-5}               # set n to $2, or default to 5
i=0                     # initialize line counter to 0

while IFS= read -r line <&3; do  # always read from input on FD 3
  if (( i % n == 0 )); then      # if we're on a line being sorted...
    IFS= read -r line <&4        # ...overwrite $line from the awk | sort process on FD 4
  fi
  printf '%s\n' "$line"          # write out whatever we most recently read 
  (( ++i ))                      # increment line counter 
done 3<"$input" 4< <(awk -v "n=$n" 'NR%n==0' <"$input" | sort -f)

一些注意事项:

  • 在脚本的第一行使用显式调用 bash(而不是 sh)的 shebang 可确保扩展可用。
  • &lt;(awk ...) 是一个进程替换——它评估为一个文件名,当读取该文件名时,将提供awk 命令的输出。 4&lt; 将该文件的内容连接到文件描述符#4。
  • (( )) 创建一个算术上下文,并且是 ksh 和 bash 提供的扩展(与 $(( )) 相比,后者由 POSIX 保证)。
  • 如需详细了解为何按原样调用 read(清除 IFS 并传递 -r 参数),请参阅 BashFAQ #001
  • 使用awk -v "var=$var" 'awk script using var' 可避免在形成具有字符串连接的脚本时可能导致的错误和注入漏洞

【讨论】:

  • 那个代码不起作用,可能有错误但我找不到它
  • @CharlesDuffy 我看到您使用的是重定向而不是read-u 选项(我认为是为了便携性)。如果 shell 是 Bash,使用 -u 有什么优点/缺点吗?
  • @Fred,没有缺点,只是没有特别的优势,而且我更喜欢仅在它们提供一些优势时才依赖 bashisms(即使该优势只是清晰)。通过使用与用于其他目的不同的语法来重定向read 的输入,我认为read -u 会降低清晰度而不是增加清晰度。
  • @SergioRey,如果您描述的不是“不起作用”,而是 如何 它失败了——输出是否错误?如果是这样,具体是通过什么方式?有消息吗?如果是这样,具体是什么? -- 那会更有用。
  • @grail,请参阅上面我对 Fred 的回复。
猜你喜欢
  • 2021-10-28
  • 2017-04-12
  • 2021-12-16
  • 2022-10-24
  • 2012-11-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-08
  • 2022-01-01
相关资源
最近更新 更多