28

Я взял книгу в формате простого текстового файла от Project Gutenberg (около 0,5 МБ), которую я хочу объединить с собой n раз, чтобы сгенерировать большой текстовый файл, с которым я могу сравнить некоторые алгоритмы. Есть ли команда Linux, которую я могу использовать для достижения этой цели? cat звучит идеально, но, кажется, не слишком хорошо играет с конкатенацией файла на себя, плюс она не затрагивает n раз часть вопроса.

3 ответа3

31

Для меня это две части - во-первых - использовать cat для вывода текстового файла в стандартный вывод и использовать append для добавления его в другой файл - например, foo.txt >> bar.txt добавит foo.txt к bar.txt

затем запустить его n раз с

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

заменив в этой команде свой номер

должно работать, где n ваш номер

Если вы используете csh, есть команда «repeat».

повторяющиеся связанные части ответа скопированы отсюда , и я проверил его в системе Ubuntu 11.04 в оболочке bash по умолчанию.

2

Вы, конечно, можете использовать cat для этого:

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

Чтобы получить $n копий, вы можете использовать yes конвейеру в head -n $n:

$ 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
1

Мне скучно, так что вот еще несколько методов, как объединить файл с самим собой, в основном с head в качестве костыля. Простите, если я переобъясню себя, я просто люблю говорить:P


Предполагая, что 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_repeats - это количество раз, которое необходимо добавить в file file2 чтобы сделать его таким же, как если бы file был сцеплен с самим собой N раз.

Сказал, что МАТ здесь, более или менее: МАТ (сущность)

Это первый семестр по информатике, но прошло уже много времени с тех пор, как я сделал доказательство индукции, поэтому я не могу с этим справиться ... (также этот класс рекурсии довольно хорошо известен как 2^Loops так что это тоже есть .. ..)


POSIX

Я использую несколько не-posix вещей, но они не являются необходимыми. Для моих целей:

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

О, я только использовал это. Ну что ж, раздел уже здесь ...


методы


head с отслеживанием linecount.

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

Нет временных файлов, нет кота, даже не слишком много математики, все радость.


tee с математикой

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

Здесь tee читает из file но постоянно добавляет к нему, так что он будет продолжать читать файл при повторении, пока head остановит его. И мы знаем, когда остановить это из-за МАТ. Добавление идет за борт, поэтому я использовал временный файл. Вы также можете обрезать лишние строки из 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

Вторая 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 читать весь файл как строку, захватывает все, а затем вставляет его $total_repeats количество раз.

Конечно, это не удастся, если в вашем файле есть нулевые символы. Выберите тот, которого вы знаете, там нет.

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
}

Пока это все, ребята, надеюсь, этот произвольный ответ никого не смутил. Я тестировал все это много раз, но я только два года пользуюсь оболочкой, так что имейте это в виду, я думаю. Сейчас спать ...

rm $tmp

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .