30000個のtxtファイルを含むフォルダがあり、各ファイルのサイズは50-60kbです。 2.5mb txt ファイルにマージする必要があります。そして、マージ中のファイルを削除してください。私のコードは次のようになります。for f in *,50; do cat file1,file2...file49 > somefile.txt;done
もちろんこれは擬似コードです。ファイルを50の束にマージしてから、使用したファイルを削除する必要があります。誰でも私を助けることができますか?
答え1
そしてzsh
:
files=( ./input-file*(Nn.) )
typeset -Z3 n=1
while
(( $#files > 0 )) &&
cat $files[1,50] > merged-file$n.txt &&
rm -f $files[1,50]
do
files[1,50]=()
((n++))
done
./input-file*(Nn.)
一致するファイルに展開されますが、./input-file*
3つのグローバル修飾子を使用してさらに分類されます。
N
:nullglob: 一致するものが存在しない場合、エラーによって中断されるのではなく、glob 拡張を null にします。 globで配列を設定するときにこれが必要であり、配列が空であっても大丈夫です。n
::numericglobsort
デフォルトの語彙ソートを数値ソート(実際には2つの組み合わせ)に変更します。言い換えれば、input-file2
フロントソートです。input-file10
.
: 限定定期的なファイル(ディレクトリ、シンボリックリンク、FIFOを無視...)
typeset -Z3 n
$n
幅が3になるまで変数を0で埋めて、次のようにしますmerged-file001.txt
。 ... merged-file049.txt
...
次に、配列に要素があり、エラーがない限り、$files
一度に50のバッチ(および最後のバッチで残っているすべての要素)を連結して繰り返します。
bash 4.4+およびGNUツールにも同じことが当てはまります。
readarray -td '' files < <(
LC_ALL=C find . -maxdepth 1 -name 'input-file*' -type f -print0 |
sort -zV
)
n=0
set -- "${files[@]}"
while
(( $# > 0 )) &&
printf -v padded_n %03d "$n" &&
cat "${@:0:50}" > "merged-file$padded_n.txt" &&
rm -f "${@:0:50}"
do
shift "$(( $# >= 50 ? 50 : $# ))"
((n++))
done
find
zshが機能している場合、./input-file*(N.)
数値sort -V
(バージョン)ソートは位置引数を使用し、配列は非常に制限されているため、shift
ループ内で配列を使用します。bash
答え2
このスクリプトは次のとおりです。
- Bashの場合(タグ付き)
- ルックアップ防止(無効な文字による失敗)
- 通常のファイル(ディレクトリなし)のみが処理されることを確認してください。
sort
数字(まあ、バージョン別)で並べ替え- 接続
k
ファイル(変数数) - 削除する一つ一度ファイル(削除されないファイルブロックのコピーを防ぐ)
dir="myDir"
readarray -td $'\0' files < <(
for f in ./"$dir"/in-file*; do
if [[ -f "$f" ]]; then printf '%s\0' "$f"; fi
done |
sort -zV
)
k=50
rm -f ./"$dir"/joined-files*.txt
for i in "${!files[@]}"; do
n=$((i/k+1))
cat "${files[i]}" >> ./"$dir"/joined-files$n.txt &&
rm -f "${files[i]}"
done