วิธีการแทนที่สตริงในบรรทัดที่ 5 ของไฟล์ข้อความหลายไฟล์?


22

ฉันต้องการแทนที่บรรทัดที่ 5 ของไฟล์ข้อความหลายไฟล์ ( file1.txt, file2.txt, file3.txt, file4.txt ) ด้วยสตริง "Good Morning" โดยใช้คำสั่งเทอร์มินัลเดียว

~/Desktopทุกไฟล์ข้อความที่มีอยู่ของฉัน

หมายเหตุ: เดสก์ท็อปของฉันประกอบด้วยไฟล์. txt 6 ไฟล์ฉันต้องการใช้การเปลี่ยนแปลงกับไฟล์ข้อความ 4 ตัวที่กล่าวถึงข้างต้นเท่านั้น

คำตอบ:


40

นี่คือแนวทางบางประการ ฉันกำลังใช้การขยายรั้ง ( file{1..4}.txt) ซึ่งหมายถึงfile1.txt file2.txt file3.txt file4.txt

  1. Perl

    perl -i -pe 's/.*/ Good Morning / if $.==5' file{1..4}.txt

    คำอธิบาย:

    • -i: ทำให้เกิดperlการแก้ไขไฟล์ในสถานที่การเปลี่ยนไฟล์ต้นฉบับ

      หาก-iตามด้วยนามสกุลท้ายของไฟล์การสำรองข้อมูลจะถูกสร้างขึ้นสำหรับทุกไฟล์ที่ถูกแก้ไข ตัวอย่าง: -i.bakสร้าง a file1.txt.bakหากfile1.txtมีการแก้ไขในระหว่างการดำเนินการ

    • -p: หมายถึงอ่านไฟล์อินพุตทีละบรรทัดใช้สคริปต์และพิมพ์

    • -e: ช่วยให้คุณสามารถส่งสคริปต์จากบรรทัดคำสั่ง

    • s/.*/ Good Morning /: นั่นจะแทนที่ข้อความในบรรทัดปัจจุบัน ( .*) ด้วย Good Morning

    • $.เป็นตัวแปร Perl พิเศษที่เก็บหมายเลขบรรทัดปัจจุบันของไฟล์อินพุต ดังนั้นs/foo/bar/ if $.==5หมายถึงแทนที่fooด้วยbarเฉพาะในบรรทัดที่ 5

  2. sed

    sed -i '5s/.*/ Good Morning /' file{1..4}.txt

    คำอธิบาย:

    • -i: perlแก้ไขไฟล์ที่ต้องการ

    ตามค่าดีฟอลต์sedพิมพ์แต่ละบรรทัดของไฟล์อินพุต 5s/pattern/replacement/รูปแบบวิธีการทดแทนด้วยการเปลี่ยนในบรรทัดที่ 5

  3. awk

    for f in file{1..4}.txt; do 
        awk 'NR==5{$0=" Good Morning "}1;' "$f" > foobar && mv foobar "$f"; 
    done

    คำอธิบาย:

    awkไม่มีตัวเลือกที่เทียบเท่ากับ-i¹ซึ่งหมายความว่าเราจำเป็นต้องสร้างไฟล์ชั่วคราว ( foobar) ซึ่งจะถูกเปลี่ยนชื่อเพื่อเขียนทับต้นฉบับ ห่วงทุบตีfor f in file{1..4}.txt; do ... ; doneเพียงแค่ผ่านไปแต่ละประหยัดชื่อไฟล์ปัจจุบันเป็นfile{1..4}.txt $fในawk, NRเป็นจำนวนบรรทัดปัจจุบันและ$0เนื้อหาของสายในปัจจุบัน ดังนั้นสคริปต์จะแทนที่บรรทัด ( $0) ด้วย "Good Morning" ในบรรทัดที่ 5 เท่านั้น 1;ใช้awkสำหรับ "พิมพ์บรรทัด"

    ¹ เวอร์ชั่นใหม่ไม่เป็น devnull แสดงให้เห็นในของเขาคำตอบ

  4. coreutils

    for f in file{1..4}.txt; do 
        (head -4 "$f"; echo " Good Morning "; tail -n +6 "$f") > foobar && 
        mv foobar "$f"; 
    done 

    คำอธิบาย:

    มีการอธิบายการวนซ้ำในส่วนก่อนหน้า

    • head -4: พิมพ์ 4 บรรทัดแรก

    • echo " Good Morning ": พิมพ์ "อรุณสวัสดิ์"

    • tail -n +6: พิมพ์ทุกอย่างจากบรรทัดที่ 6 ถึงท้ายไฟล์

    วงเล็บ( )รอบคำสั่งทั้งสามนี้ช่วยให้คุณสามารถจับเอาท์พุทของทั้งสาม (ดังนั้น 1 บรรทัดที่ 4 แล้วตามด้วย "อรุณสวัสดิ์" จากนั้นตามด้วยส่วนที่เหลือของบรรทัด) และเปลี่ยนเส้นทางไปยังไฟล์


23

คุณสามารถใช้sed:

sed '5s/^/Good morning /' file

จะต่อท้ายGood morningบรรทัดที่ห้าของไฟล์

หากคุณต้องการแทนที่เนื้อหาในบรรทัด 5 แทนให้พูดว่า:

sed '5s/.*/Good morning/' file

หากคุณต้องการบันทึกการเปลี่ยนแปลงในไฟล์ให้ใช้-iตัวเลือก:

sed -i '5s/.*/Good morning/' file

sedสามารถจัดการไฟล์ได้มากกว่าหนึ่งไฟล์ในแต่ละครั้ง คุณสามารถเพิ่มชื่อไฟล์เพิ่มเติมได้ที่ส่วนท้ายของคำสั่ง คุณยังสามารถใช้การขยาย bash เพื่อจับคู่ไฟล์เฉพาะ:

# manually specified
sed -i '5s/.*/Good morning/' file1.txt file2.txt file3.txt file4.txt

# wildcard: all files on the desktop
sed -i '5s/.*/Good morning/' ~/Desktop/*

# brace expansion: file1.txt, file2.txt, file3.txt, file4.txt
sed -i '5s/.*/Good morning/' file{1..4}.txt

คุณสามารถอ่านข้อมูลเพิ่มเติมเกี่ยวกับการขยายรั้งที่นี่


GNU awk รุ่น 4.1.0 ขึ้นไปมาพร้อมกับส่วนขยายที่เปิดใช้งานการแก้ไขในสถานที่ ดังนั้นคุณสามารถพูดได้:

gawk -i inplace 'NR==5{$0="Good morning"}7' file

เพื่อแทนที่บรรทัด # 5 ในไฟล์ด้วยGood morning!


2

ฉันไม่เห็นวิธีแก้ปัญหาของงูหลามดังนั้นนี่คือ:

import sys
import os
def open_and_replace(filename):

    with open(filename) as read_file:
        temp = open("/tmp/temp.txt","w")
        for index,line in enumerate(read_file,1):
            if  index == 5:
                temp.write("NEW STRING\n")
            else:
                temp.write(line.strip() + "\n")
        temp.close()
    os.rename("/tmp/temp.txt",filename)

for file_name in sys.argv[1:]:
    open_and_replace(file_name)

แนวคิดพื้นฐานคือสำหรับแต่ละไฟล์ที่ให้ไว้ในบรรทัดคำสั่งเป็นอาร์กิวเมนต์เราเขียนไฟล์ชั่วคราวและระบุแต่ละบรรทัดในไฟล์ต้นฉบับ หากดัชนีของเส้นเป็น 5 เราจะเขียนบรรทัดที่แตกต่างกัน ที่เหลือก็แค่แทนที่ไฟล์เก่าด้วยไฟล์ temp Demo:

$> ls
file1.txt  file2.txt  file3.txt
$> cat file1.txt                                                               
line 1
line 2
line 3
line 4
GOOD MORNING
line 6
$> python ~/replace_5th_line.py file1.txt file2.txt  file3.txt                 
$> cat file1.txt                                                               
line 1
line 2
line 3
line 4
NEW STRING
line 6
$> cat file2.txt                                                               
line 1
line 2
line 3
line 4
NEW STRING
line 6

เดียวกันสามารถทำได้ด้วยความเข้าใจในรายการ ด้านล่างเป็นหนึ่งในสายการบินของสคริปต์เดียวกัน:

cat /etc/passwd | python -c 'import sys; print "\n".join(["CUSTOM"  if index == 5 else line.strip() for index,line in enumerate(sys.stdin,1)])'

หรือไม่ cat

python -c 'import sys; print "\n".join(["CUSTOM"  if index == 5 else line.strip() for index,line in enumerate(sys.stdin,1)])' < /etc/passwd

สิ่งที่เหลืออยู่ก็คือการเปลี่ยนเส้นทางของเนื้อหาที่แก้ไขไปยังไฟล์อื่นด้วย > output.txt


1

คุณสามารถใช้ Vim ในโหมด Ex:

for b in 1 2 3 4
do
  ex -sc '5c|Good Morning' -cx file"$b".txt
done
  1. 5 เลือกบรรทัดที่ 5

  2. c แทนที่ข้อความ

  3. x เขียนถ้ามีการเปลี่ยนแปลง (พวกเขามี) และออกจาก


0

ต่อไปนี้เป็นสคริปต์ทุบตีซึ่งล้อมรอบ กระบวนการ Perl ที่แนะนำในคำตอบนี้

ตัวอย่าง:

/ tmp / มัน

console:
  enabled:false

จากนั้นเรียกใช้สิ่งต่อไปนี้:

$ search_and_replace_on_line_of_file.sh false true 2 /tmp/it

และตอนนี้ไฟล์มี

/ tmp / มัน

console:
  enabled:true

search_and_replace_on_line_of_file.sh

function show_help()
{
  IT=$(CAT <<EOF

  usage: SEARCH REPLACE LINE_NUM FILE

  e.g. 

  false true 52 /tmp/it  -> replaces false with true on line 52 of file /tmp/it

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ -z "$4" ]
then
  show_help
fi

SEARCH_FOR=$1
REPLACE_WITH=$2
LINE_NO=$3
FILE_NAME=$4
perl -i -pe "s/$SEARCH_FOR/$REPLACE_WITH/ if $.==$LINE_NO" $FILE_NAME 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.