คำสั่ง Linux เพื่อต่อไฟล์เข้ากับตัวเอง n ครั้ง


31

ฉันได้รับหนังสือไฟล์ข้อความธรรมดาจาก Project Gutenberg (ประมาณ 0.5MB) ซึ่งฉันต้องการเชื่อมต่อกับnเวลาของตัวเองเพื่อสร้างไฟล์ข้อความขนาดใหญ่ที่ฉันสามารถสร้างมาตรฐานอัลกอริธึมได้บ้าง มีคำสั่ง linux ที่ฉันสามารถใช้เพื่อให้บรรลุนี้ catฟังดูดี แต่ดูเหมือนจะไม่เล่นดีเกินไปเมื่อต่อไฟล์เข้ากับตัวเองบวกกับไม่ได้บอกnเวลาโดยตรงในส่วนของคำถาม


2
ใช้วนรอบบางอย่างแล้วต่อท้าย? ดังนั้น foo.txt >> bar.txt ซ้ำแล้วซ้ำอีกในสิ่งที่จะเรียกใช้คำสั่งที่หลายต่อหลายครั้ง?
Geek

คำตอบ:


35

สำหรับฉันส่วนแรก - เพื่อใช้ cat เพื่อส่งออกไฟล์ข้อความไปยังเอาต์พุตมาตรฐานและใช้ผนวกเพื่อเพิ่มไปยังไฟล์อื่น - เช่น foo.txt >> bar.txt จะผนวก foo.txt ไปที่ bar.txt

จากนั้นรันด้วย n ครั้งด้วย

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

แทนที่ n ในคำสั่งนั้นด้วยหมายเลขของคุณ

ควรทำงานโดยที่ n คือหมายเลขของคุณ

หากคุณใช้ csh มีคำสั่ง 'ซ้ำ'

ทำซ้ำส่วนที่เกี่ยวข้องของคำตอบจะถูกคัดลอกจากที่นี่และฉันทดสอบบนระบบ Ubuntu 11.04 บนเปลือกทุบตีเริ่มต้น


3
ความจริงแล้วสนุก: มันใช้งานได้จริงโดยไม่ต้องแทนที่ 'n' ซึ่งในกรณีนี้มันจะเรียกใช้เนื้อความหนึ่งครั้งสำหรับแต่ละอักขระระหว่าง ASCII '1' และ ASCII 'n' (เช่น 62 ครั้ง) แต่{1..12}จะวิ่งร่างกายอย่างถูกต้อง 12 ครั้ง
Arnout Engelen

1
คุณอาจต้องการเปลี่ยนเส้นทางไปป์ไลน์ทั้งหมดแทนที่จะเพิ่มในแต่ละการวนซ้ำ:for i in {1..n};do cat foo.txt; done > bar.txt
Toby Speight

2

ฉันเบื่อดังนั้นนี่คือวิธีการอีกสองสามวิธีเกี่ยวกับการเชื่อมไฟล์เข้ากับตัวเองซึ่งส่วนใหญ่headเป็นไม้ยันรักแร้ ให้อภัยฉันถ้าฉันอธิบายตัวเองให้มากเกินไปฉันแค่ชอบพูดสิ่งต่าง ๆ : พี


สมมติว่าNเป็นจำนวน concatenations 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ครั้ง

กล่าวว่าMATHอยู่ที่นี่ไม่มากก็น้อย: MATH (ส่วนสำคัญ)

มันเป็นสิ่งที่ภาคการศึกษาแรกวิทยาการคอมพิวเตอร์ แต่จะได้รับในขณะที่ตั้งแต่ผมทำหลักฐานการเหนี่ยวนำดังนั้นฉันไม่สามารถได้รับมากกว่านั้น ... (ยังเป็นระดับของการเรียกซ้ำนี้สวยที่รู้จักกันดีที่จะเป็น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

ไม่มีไฟล์ temp, cat ไม่มีแม้แต่คณิตศาสตร์มากเกินไปความสุขทั้งหมด


teeกับMATH

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

นี่teeคือการอ่านจากfileแต่จะต่อท้ายตลอดดังนั้นมันจะทำการอ่านไฟล์ซ้ำจนกว่าheadจะหยุด และเรารู้ว่าเมื่อมีการหยุดมันเพราะMATH การต่อท้ายผ่านไปผมก็เลยใช้ไฟล์ temp คุณสามารถตัดขอบส่วนเกินได้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


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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.