複数のファイルに「切り取り」を適用してから結果を「貼り付け」する方法は?

複数のファイルに「切り取り」を適用してから結果を「貼り付け」する方法は?

私はこれを頻繁にします

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 グローバル予選、 plus 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

私はあなたの最初の行が単純な1行ほど良いと思います。

名前の異なる複数のファイルがある場合は、単純な履歴拡張「チート」を使用して重複入力を減らすことができます。

最初の実行<(cut -d, -f1

末尾のスペースに注意してください。また、このコマンドはCtrl-を押すだけで補助プロンプトが表示されることに注意してくださいC。唯一のことは歴史に追加することです。

次の実行paste !!file1.csv) !!file2.csv)

!!末尾の空白を含む、前のコマンド実行の全内容に拡張されます。末尾の閉じ括弧を忘れた場合は、補助プロンプトが表示されます。その場合は、Ctrl-と入力してCもう一度やり直してください。

少し古いですが、使い捨てで使用するのに十分です。これを頻繁に行うと、bash関数を書くことができます。

答え3

努力するアッ

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 ) " "$@")"

それは行わなければなりません。

関連情報