web-dev-qa-db-ja.com

ファイルをn回連結するLinuxコマンド

いくつかのアルゴリズムをベンチマークできる大きなテキストファイルを生成するために、Project Gutenbergからプレーンテキストファイルの本(約0.5MB)を自分でn回連結したいと考えています。これを達成するために使用できるLinuxコマンドはありますか? catは理想的に聞こえますが、ファイルをそれ自体に連結することはあまりうまくいきませんし、質問のn回の部分に直接対処しません。

31
Bryce Thomas

これには2つの部分があります-最初に-catを使用してテキストファイルを標準出力に出力し、appendを使用してそれを別のファイルに追加します。たとえば、foo.txt >> bar.txtはfoo.txtをbar.txtに追加します

次にそれをn回実行します

for i in {1..n};do cat foo.txt >> bar.txt; done

そのコマンドのnを自分の番号に置き換えます

nはあなたの数です

Cshを使用する場合、 'repeat'コマンドがあります。

回答の繰り返し関連部分はここからコピーされます 、そして私はそれをデフォルトのbashシェルのubuntu 11.04システムでテストしました。

35
Journeyman Geek

これには確かにcatを使用できます。

$ cat /tmp/f
foo
$ cat /tmp/foo /tmp/f
foo
foo

$nのコピーを取得するには、head -n $nにパイプされたyesを使用できます。

$ yes /tmp/f | head -n 10
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f

まとめると

yes /tmp/f | head -n $n | xargs cat >/tmp/output
2
Toby Speight

私は退屈なので、ファイルをそれ自体に連結する方法についていくつかの方法を紹介します。主にheadを松葉杖として使用しています。私が自分で言いすぎた場合は、ご容赦ください。


Nは、実行する自己連結の数であり、ファイルの名前はfileであると仮定します。

変数:

linecount=$(<file wc -l)

total_repeats=$(echo "2^$N - 1" | bc) # obtained through the power of MATH

total_lines=$((linecount*(total_repeats+1)))

tmp=$(mktemp --suffix .concat.self)

fileのコピーをfile2とすると、total_repeatsfilefile2に追加して、 fileがそれ自体にN回連結された場合。

上記[〜#〜] math [〜#〜]がここにあります、多かれ少なかれ: MATH(Gist)

それは最初の学期のコンピュータサイエンスのものですが、帰納証明を行ってからそれを乗り越えることができないので久しぶりです(また、このクラスの再帰は2^Loopsであることがよく知られているので、それもあります....)


[〜#〜] posix [〜#〜]

私はいくつかの非POSIXのものを使用しますが、それらは必須ではありません。私の目的のために:

 yes() { while true; do echo "$1"; done; }

ああ、私はそれだけを使いました。ああ、セクションはすでにここにあります...


方法


headと行数の追跡。

ln=$linecount
for i in $(seq 1 $N); do
    <file head -n $ln >> file;
    ln=$((ln*2))
done

一時ファイルも、猫も、数学もあまりありません。


tee with[〜#〜]数学[〜#〜]

<file tee -a file | head -n $total_lines > $tmp
cat $tmp > file

ここでteefileから読み取りを行っていますが、永続的に追加しているため、headが停止するまで繰り返しファイルを読み取り続けます。そして、[〜#〜] math [〜#〜]のため、いつ停止するかがわかります。追加はオーバーボードになるため、一時ファイルを使用しました。 fileから余分な行を削除することもできます。


闇の支配者、eval

eval "cat $(yes file | head -n $((total_repeats+1)) | tr '\n' ' ')" > $tmp
cat $tmp > file

これはcat file file file ...に展開され、評価されます。 $tmpファイルがなくても実行できます。

eval "cat $(yes file | head -n $total_repeats | tr '\n' ' ')" |
  head -n $((total_lines-linecount)) >> file

2番目のhead "トリック" catは、それと書き込み操作の間に中間者を置くことによって。 catを別のcatでだますこともできますが、動作に一貫性がありません。これを試して:

test_double_cat() {
    local Expected=0
    local Got=0
    local R=0
    local file="$(mktemp --suffix .double.cat)"
    for i in $(seq 1 100); do

        printf "" > $file
        echo "1" >> $file
        echo "2" >> $file
        echo "3" >> $file

        Expected=$((3*$(<file wc -l)))

        cat $file $file | cat >> $file

        Got=$(<file wc -l)

        [ "$Expected" = "$Got" ] && R="$((R+1))"
    done
    echo "Got it right $R/100"
    rm $file
}

sed

<file tr '\n' '\0' |
    sed -e "s/.*/$(yes '\0' | head -n $total_repeats | tr -d '\n')/g" |
        tr '\0' '\n' >> file

sedにファイル全体を1行として読み取らせ、すべてをキャプチャしてから、$total_repeatsの回数だけ貼り付けます。

もちろん、ファイルにnull文字がある場合は失敗します。存在しないことがわかっているものを1つ選択してください。

find_missing_char() {
  local file="${1:-/dev/stdin}"

  firstbyte="$(<$file fold -w1 | od -An -tuC | sort -un | head -n 1)"
  if [ ! "$firstbyte" = "0" ]; then
    echo "\0"
  else
    printf "\\$(printf '%03o\t' $((firstbyte-1)) )"
  fi
}

今のところこれですべてです。この恣意的な答えが誰も気にしないことを願っています。私はそれらすべてを何度もテストしましたが、私は2年間のShellユーザーなので、覚えておいてください。寝よう...

rm $tmp

2
phicr