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

sha*_*ker 9 zsh cut paste

我经常做这样的操作

paste <(cut -d, -f1 file1.csv) <(cut -d, -f1 file2.csv)
Run Code Online (Sandbox Code Playgroud)

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

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

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

但我不确定如何从那里开始。

Gil*_*il' 5

您可以使用 globbing 自动执行此操作,特别是e glob qualifier , plus eval,但它不漂亮而且引用很棘手:

eval paste *.csv(e\''REPLY="<(cut -d, -f1 $REPLY)"'\')
Run Code Online (Sandbox Code Playgroud)
  • 两者之间的部分\'…\'是为 glob 的每个匹配执行的一些代码。它与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)^@})"
}
Run Code Online (Sandbox Code Playgroud)

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

map paste -- cut -d, -f1 -- *.csv
Run Code Online (Sandbox Code Playgroud)