Lệnh Linux để nối một tệp với chính nó n lần


31

Tôi đã lấy một cuốn sách tệp văn bản đơn giản từ Project Gutenberg (khoảng 0,5 MB) mà tôi muốn ghép nối với chính nó nđể tạo ra một tệp văn bản lớn mà tôi có thể điểm chuẩn một số thuật toán. Có một lệnh linux tôi có thể sử dụng để đạt được điều này? catNghe có vẻ lý tưởng, nhưng dường như không chơi quá hay với việc ghép một tệp vào chính nó, cộng với việc không trực tiếp giải quyết phần nthời gian của câu hỏi.


2
sử dụng một số loại vòng lặp, và nối thêm? Vì vậy, lặp lại foo.txt >> bar.txt và gói nó trong một cái gì đó sẽ chạy lệnh đó nhiều lần?
Journeyman Geek

Câu trả lời:


35

Đối với tôi, hai phần này - trước tiên - sử dụng cat để xuất tệp văn bản thành đầu ra tiêu chuẩn và sử dụng chắp thêm để thêm nó vào một tệp khác - ví dụ: foo.txt >> bar.txt sẽ nối foo.txt vào bar.txt

sau đó chạy nó n lần với

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

thay n trong lệnh đó bằng số của bạn

nên làm việc, trong đó n là số của bạn

Nếu bạn sử dụng csh, sẽ có lệnh 'lặp lại'.

lặp lại các phần liên quan của câu trả lời được sao chép từ đây và tôi đã thử nó trên hệ thống ubfox 11.04 trên vỏ bash mặc định.


3
Sự thật thú vị: điều này thực sự hoạt động mà không cần thay thế 'n', trong trường hợp đó, nó sẽ thực thi cơ thể một lần cho mỗi ký tự giữa ASCII '1' và ASCII 'n' (vì vậy 62 lần). Nhưng {1..12}sẽ chạy chính xác cơ thể 12 lần.
Arnout Engelen

1
Bạn có thể muốn chuyển hướng toàn bộ đường ống, thay vì nối thêm vào mỗi lần lặp:for i in {1..n};do cat foo.txt; done > bar.txt
Toby Speight

2

Tôi thấy chán vì vậy đây là một vài phương pháp nữa về cách ghép một tệp với chính nó, chủ yếu là với headmột cái nạng. Xin lỗi nếu tôi thể hiện quá mức bản thân, tôi chỉ thích nói những điều: P


Giả sử Nlà số lượng tự ghép bạn muốn làm và tệp của bạn được đặt tên file.

Biến:

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)

Cho một bản sao của cuộc filegọi file2, total_repeatslà số lần filesẽ cần phải được thêm vào file2để làm cho nó giống như khi fileđược nối với Nthời gian của chính nó .

MATH đã nói ở đây, ít nhiều: MATH (ý chính)

Đó là công cụ khoa học máy tính học kỳ đầu tiên nhưng đã được một thời gian kể từ khi tôi làm bằng chứng cảm ứng nên tôi không thể vượt qua nó ... (cũng là lớp đệ quy này khá nổi tiếng 2^Loopsnên cũng vậy ....)


POSIX

Tôi sử dụng một vài thứ không phải là posix nhưng chúng không cần thiết. Đối với mục đích của tôi:

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

Ồ, tôi chỉ sử dụng nó. Ồ, phần này đã ở đây ...


Phương pháp


head với theo dõi linecount.

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

Không có tập tin tạm thời, không có con mèo, thậm chí không có quá nhiều toán học, tất cả niềm vui.


teevới MATH

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

Đây teelà đọc từ filenhưng liên tục nối vào nó, vì vậy nó sẽ tiếp tục đọc tệp lặp lại cho đến khi headdừng nó. Và chúng tôi biết khi nào nên dừng nó vì MATH . Việc nối thêm quá mức, vì vậy tôi đã sử dụng tệp tạm thời. Bạn có thể cắt các dòng thừa từ filequá.


eval, chúa tể bóng tối!

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

Điều này chỉ mở rộng cat file file file ...và đánh bại nó. Bạn cũng có thể làm điều đó mà không cần $tmptập tin:

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

head"Thủ thuật" thứ hai catbằng cách đặt một người trung gian giữa nó và thao tác ghi. Bạn cũng có thể lừa catngười khác catnhưng điều đó có hành vi không nhất quán. Thử đi:

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

Buộc sedđọc toàn bộ tập tin dưới dạng một dòng, ghi lại tất cả, sau đó dán $total_repeatssố lần.

Tất nhiên điều này sẽ thất bại nếu bạn có bất kỳ ký tự null nào trong tệp của mình. Chọn một cái mà bạn biết là không có ở đó.

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
}

Đó là tất cả cho đến bây giờ, tôi hy vọng câu trả lời độc đoán này đã không làm phiền bất cứ ai. Tôi đã thử nghiệm tất cả chúng nhiều lần nhưng tôi chỉ là người dùng shell hai năm nên tôi nhớ điều đó. Bây giờ đi ngủ ...

rm $tmp


2

Bạn chắc chắn có thể sử dụng catcho việc này:

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

Để có được $nbản sao, bạn có thể sử dụng yesđường ống vào 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

Đặt nó cùng nhau mang lại

yes /tmp/f | head -n $n | xargs cat >/tmp/output
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.