读取每个文件并执行循环中的func

时间:2014-02-20 14:06:43

标签: c shell

我的硬盘中有5000个文件,名称为ip_file_1,ip_file_2,.... 我有一个只能合并2个文件的可执行文件。如何编写一个脚本,该脚本将所有文件驻留在硬盘中(以ip_file_ *开头)并调用该函数合并所有文件。

我有5000个文件,它们是包含日志记录信息的二进制文件(每个函数调用所花费的时间)。我有另一个可执行文件,它只接受两个文件并根据时间戳合并并给出合并的输出。

我使用以下格式执行

./trace ip_file1 ip_file2 mergefile  # I'm not using the trace tool. It's an example

我可以使用可执行文件仅合并两个文件。我想将其自动化以合并所有其他文件。

合并必须按顺序完成(根据时间戳合并)。合并的逻辑已经存在。并且合并的输出将发送到文件。

我的问题不在于如何合并文件。我的问题是如何自动化和合并所有文件而不是两个文件。

2 个答案:

答案 0 :(得分:1)

为了避免过多的参数或命令行的参数长度,您希望编写merge命令,以便它可以采用先前合并的输出并合并另一个文件。原始问题陈述中merge的描述很少,所以我假设您可以这样做:

 merge -o output_file input_file

output_file可以是先前合并的文件或新文件。如果你能做到这一点,那么将所有这些合并起来很简单:

find drive_path -name "ip_file_*" -exec merge -o output_file {} \;

此处的顺序是文件系统中的目录顺序。如果需要不同的订单,则需要指定。

<强>附录

如果您需要按时间戳顺序排列的文件,那么我将修改此方法并创建一个merge命令,该命令接受一个文本文件作为输入,该文件列出了要合并的所有文件。使用此帖子中提供的信息创建此文件列表:https://superuser.com/questions/294161/unix-linux-find-and-sort-by-date-modified

答案 1 :(得分:1)

如果您的外部合并工具是real_merge,并且此工具将两个命令行参数的合并输出写入stdout,则以下递归shell函数将执行此任务:

merge_files() {
  next=$1; shift
  case $# in
    0) cat "$next" ;;
    1) real_merge "$next" "$1"
    *) real_merge "$next" <(merge_files "$@")
  esac
}

这种方法是高度并行化的 - 这意味着它将使用尽可能多的CPU和磁盘IO。根据您的可用资源以及您的操作系统管理这些资源的工具,这可能是也可能不是一件好事。

另一种方法是使用临时文件:

swap() {
  local var_curr=$1
  local var_next=$2
  local tmp

  tmp="${!var_curr}"
  printf -v "$var_curr" "${!var_next}"
  printf -v "$var_next" "$tmp"
}

merge_files() {
  local tempfile_curr=tempfile_A
  local tempfile_next=tempfile_B
  local tempfile_A="$(mktemp -t sort-wip-A.XXXXXX)"
  local tempfile_B="$(mktemp -t sort-wip-B.XXXXXX)"
  while (( $# )); do
    if [[ -s ${!tempfile_curr} ]]; then
      # we already populated our temporary file
      real_merge "${!tempfile_curr}" "$1" "${!tempfile_next}"
      swap tempfile_curr tempfile_next
    elif (( $# >= 2 )); then
      # only two arguments at all
      real_merge "$1" "$2" "${!tempfile_curr}"
      shift
    else
      # only one argument at all
      cat "$1"
      rm -f "$tempfile_A" "$tempfile_B"
      return
    fi
    shift
  done
  # write output to stdout
  cat "${!tempfile_curr}"
  # ...and clean up.
  rm -f "$tempfile_A" "$tempfile_B"
}

如果文件名的词法排序顺序准确,您可以将其调用为:merge_files ip_file_*。 (如果他们的名字是零填充的,即。ip_file_00001,则会出现这种情况,但如果没有填充,则为真。)如果没有,您需要先对名称流进行排序。如果您正在使用bash并且可以使用GNU统计和排序,则可以这样做:

declare -a filenames=()
while IFS='' read -r -d ' ' timestamp && IFS='' read -r -d '' filename; do
  filenames+=( "$filename" )
done < <(stat --printf '%Y %n\0' ip_file_* | sort -n -z)
merge_files "${filenames[@]}"