如何将“剪切”应用于多个文件,然后“粘贴”结果?

如何将“剪切”应用于多个文件,然后“粘贴”结果?

我经常做这样的操作

paste <(cut -d, -f1 file1.csv) <(cut -d, -f1 file2.csv)

对于多个文件来说,这是非常乏味的。

我可以自动化这个过程,例如通过通配符吗?我可以保存cut结果

typeset -A cut_results
for f in file*.csv; do
    cut_results[$f]="$(cut -d, -f1 $f)"
done

但我不知道如何从那里开始。

答案1

您可以通过通配符自动执行此操作,特别是e 全局限定符,加上eval,但它并不漂亮,而且引用也很棘手:

eval paste *.csv(e\''REPLY="<(cut -d, -f1 $REPLY)"'\')
  • 之间的部分\'…\'是为全局的每个匹配执行的一些代码。它是在变量REPLY设置为匹配的情况下执行的,并且可以修改它。
  • 我将代码放在单引号中,以便在解析 glob 时它不会扩展。
  • 如果匹配为 ,则代码REPLY="<(cut -d, -f1 $REPLY)"生成字符串。双引号是必需的,这样除了替换 的值之外,执行代码时等号后面的部分不会展开。<(cut -d, -f1 file1.csv)file1.csveREPLY
  • 由于每个通配文件都被一个字符串替换,

将复杂性隐藏在函数中会更好。经过最低限度的测试。

function map {
  emulate -LR zsh
  local cmd pre
  cmd=()
  while [[ $# -ne 0 && $1 != "--" ]]; do
    cmd+=($1)
    shift
  done
  if ((!$#)); then
    echo >&2 "Usage: $0: COMMAND [ARGS...] -- PREPROCESSOR [ARGS...] -- FILES..."
    return 125
  fi
  shift
  while [[ $# -ne 0 && $1 != "--" ]]; do
    pre+="${(q)1} "
    shift
  done
  if ((!$#)); then
    echo >&2 "Usage: $0: COMMAND [ARGS...] -- PREPROCESSOR [ARGS...] -- FILES..."
    return 125
  fi
  shift
  eval "${(@q)cmd}" "<($pre${(@q)^@})"
}

示例用法(语法让人想起zargs):

map paste -- cut -d, -f1 -- *.csv

答案2

我认为你的第一行对于一个简单的单行来说已经是最好的了。

如果有一堆具有不同名称的文件,您可以使用简单的历史扩展“作弊”来减少重复输入:

第一次运行<(cut -d, -f1

注意尾随空格。另请注意,此命令将为您提供辅助提示;只需按Ctrl- C。唯一的一点是将其添加到历史记录中。

下次运行paste !!file1.csv) !!file2.csv)

!!扩展到上一个命令运行的完整内容,包括尾随空格。请注意,如果您忘记了尾随的右括号,您将收到辅助提示;如果发生这种情况,您可以输入Ctrl-C并重试。

这有点老套,但对于一次性使用来说已经足够了。如果您经常这样做,您可能会编写一个 bash 函数。

答案3

尝试awk

awk '{L[FNR]=L[FNR] $1 "\t"}END{for(i=1;i<=FNR;i++)print L[i]}' *.csv

或者粘贴sed

paste *.csv | sed 's/ [^\t]*//g'

答案4

假设你的论点在"$@",我相信类似:

eval "paste $(printf "<( cut -d, -f1 %q ) " "$@")"

应该这样做。

相关内容