ค้นหาและแทนที่ข้อความภายในไฟล์โดยใช้คำสั่ง


คำตอบ:


1053
sed -i 's/original/new/g' file.txt

คำอธิบาย:

  • sed = กระแสบรรณาธิการ
  • -i = in-place (เช่นบันทึกกลับไปที่ไฟล์ต้นฉบับ)
  • สตริงคำสั่ง:

    • s = คำสั่งทดแทน
    • original = นิพจน์ทั่วไปที่อธิบายคำเพื่อแทนที่ (หรือเพียงแค่คำนั้น ๆ )
    • new = ข้อความที่จะแทนที่ด้วย
    • g = global (เช่นแทนที่ทั้งหมดและไม่ใช่เพียงแค่การเกิดขึ้นครั้งแรก)
  • file.txt = ชื่อไฟล์


3
@Akiva หากคุณใส่อักขระพิเศษ regexในการค้นหาของคุณsedจะจับคู่ เพิ่มการ-rตั้งค่าสถานะถ้าคุณต้องการใช้ REs แบบขยายแทน
cscarney

32
@mcExchange หากเป็น/อักขระเฉพาะที่คุณต้องการจับคู่คุณสามารถใช้อักขระอื่นเป็นตัวคั่น (เช่น's_old/text_new/text_g') มิฉะนั้นคุณสามารถใส่\ ก่อนที่$ * . [ \ ^จะได้รับตัวอักษร
cscarney

3
@BrianZ เท่าที่ระบบไฟล์กังวลเอาต์พุตของ sed เป็นไฟล์ใหม่ที่มีชื่อเดียวกัน เป็นหนึ่งในข้อผิดพลาดที่รายงานโดยทั่วไปที่ไม่ใช่ข้อผิดพลาด
cscarney

16
คำสั่ง OSX sed -i '.bak' 's/original/new/g' file.txtยังสามารถเรียกใช้ด้วยส่วนขยายที่มีความยาวเป็นศูนย์sed -i '' 's/original/new/g' file.txtซึ่งจะไม่สร้างการสำรองข้อมูล
Kirk

19
ผู้ใช้ MacOS จะต้องเพิ่ม '' "after -i เป็นพารามิเตอร์สำหรับ -i ed.gs/2016/01/26/os-x-sed-invalid-command-codeเพื่อให้ไฟล์นั้นถูกเขียนทับ
geoyws

32

มีหลายวิธีในการทำเช่นนี้ หนึ่งคือการใช้sedและ Regex SED เป็นเครื่องมือแก้ไขกระแสข้อมูลสำหรับกรองและแปลงข้อความ ตัวอย่างหนึ่งมีดังนี้:

marco@imacs-suck: ~$ echo "The slow brown unicorn jumped over the hyper sleeping dog" > orly
marco@imacs-suck: ~$ sed s/slow/quick/ < orly > yarly
marco@imacs-suck: ~$ cat yarly
The quick brown unicorn jumped over the hyper sleeping dog

อีกวิธีหนึ่งซึ่งอาจสมเหตุสมผลมากกว่า< strinและ> stroutอยู่กับท่อ!

marco@imacs-suck: ~$ cat yarly | sed s/unicorn/fox/ | sed s/hyper/lazy/ > nowai
marco@imacs-suck: ~$ cat nowai 
The quick brown fox jumped over the lazy sleeping dog

6
หมายเหตุcatในcat file | sed '...'ไม่จำเป็น sed '...' fileโดยตรงคุณสามารถพูดได้
fedorqui

1
อันที่จริงสิ่งนี้สามารถลดลงได้อีก: sed -i'.bak' -e 's/unicorn/fox/g;s/hyper/brown/g' yarlyจะใช้ไฟล์ yarly และทำการเปลี่ยนแปลง 2 อย่างในขณะทำการสำรองข้อมูล การใช้time bash -c "$COMMAND"เป็นครั้งคราวแสดงให้เห็นว่าเวอร์ชั่นนี้เร็วกว่า ~ 5 เท่า
pbhj

23

มีหลายวิธีที่จะทำให้สำเร็จ ขึ้นอยู่กับความซับซ้อนของสิ่งที่เราพยายามทำให้สำเร็จด้วยการแทนที่สตริงและขึ้นอยู่กับเครื่องมือที่ผู้ใช้คุ้นเคยวิธีการบางอย่างอาจเป็นที่ต้องการมากกว่าวิธีอื่น

ในคำตอบนี้ฉันใช้input.txtไฟล์อย่างง่ายซึ่งคุณสามารถใช้เพื่อทดสอบตัวอย่างทั้งหมดที่มีให้ที่นี่ เนื้อหาของไฟล์:

roses are red , violets are blue
This is an input.txt and this doesn't rhyme

ทุบตี

ทุบตีไม่ได้หมายจริงๆสำหรับการประมวลผลข้อความ แต่แทนง่ายสามารถทำได้ผ่านทางขยายตัวพารามิเตอร์${parameter/old_string/new_string}โดยเฉพาะอย่างยิ่งที่นี่เราสามารถใช้โครงสร้างที่เรียบง่าย

#!/bin/bash
while IFS= read -r line
do
    case "$line" in
       *blue*) printf "%s\n" "${line/blue/azure}" ;;
       *) printf "%s\n" "$line" ;;
    esac
done < input.txt

สคริปต์ขนาดเล็กนี้ไม่ได้แทนที่แบบเดิมหมายความว่าคุณจะต้องบันทึกข้อความใหม่เป็นไฟล์ใหม่และกำจัดไฟล์เก่าหรือ mv new.txt old.txt

หมายเหตุด้านข้าง: หากคุณอยากรู้ว่าทำไมถึงwhile IFS= read -r ; do ... done < input.txtใช้มันเป็นวิธีการอ่านไฟล์แบบทีละบรรทัด ดูสิ่งนี้สำหรับการอ้างอิง

AWK

AWK ซึ่งเป็นยูทิลิตี้การประมวลผลข้อความค่อนข้างเหมาะสมสำหรับงานดังกล่าว มันสามารถทำได้ง่ายและเปลี่ยนคนมากขึ้นสูงขึ้นอยู่กับการแสดงออกปกติ มันมีสองฟังก์ชั่น: และsub() gsub()อันแรกแทนที่เฉพาะเหตุการณ์แรกเท่านั้นในขณะที่สอง - แทนที่เกิดขึ้นในทั้งสาย ตัวอย่างเช่นถ้าเรามีสตริงone potato two potatoนี่จะเป็นผลลัพธ์:

$ echo "one potato two potato" | awk '{gsub(/potato/,"banana")}1'
one banana two banana

$ echo "one potato two potato" | awk '{sub(/potato/,"banana")}1'                                      
one banana two potato 

AWK สามารถใช้ไฟล์อินพุตเป็นอาร์กิวเมนต์ได้ดังนั้นการทำสิ่งเดียวกันกับinput.txtจะทำได้ง่าย:

awk '{sub(/blue/,"azure")}1' input.txt

ขึ้นอยู่กับรุ่นของ AWK ที่คุณมีอาจจะมีหรือไม่มีการแก้ไขแทนดังนั้นการฝึกตามปกติคือการบันทึกและแทนที่ข้อความใหม่ ตัวอย่างเช่นสิ่งนี้:

awk '{sub(/blue/,"azure")}1' input.txt > temp.txt && mv temp.txt input.txt

SED

Sed เป็นตัวแก้ไขบรรทัด นอกจากนี้ยังใช้นิพจน์ทั่วไป แต่สำหรับการทดแทนอย่างง่ายก็เพียงพอแล้วที่จะทำ:

sed 's/blue/azure/' input.txt

สิ่งที่ดีเกี่ยวกับเครื่องมือนี้ก็คือมันมีการแก้ไขในสถานที่ซึ่งคุณสามารถเปิดใช้งานด้วยการ-iตั้งค่าสถานะ

Perl

Perl เป็นอีกเครื่องมือหนึ่งที่ใช้สำหรับการประมวลผลข้อความ แต่เป็นภาษาที่ใช้ทั่วไปและใช้ในระบบเครือข่ายการดูแลระบบแอปเดสก์ท็อปและสถานที่อื่น ๆ อีกมากมาย มันยืมแนวคิด / คุณสมบัติมากมายจากภาษาอื่นเช่น C, sed, awk และอื่น ๆ การทดแทนอย่างง่ายสามารถทำได้ดังนี้:

perl -pe 's/blue/azure/' input.txt

เช่นเดียวกับ sed, perl ยังมีแฟล็ก -i

หลาม

ภาษานี้มีความหลากหลายและใช้ในแอพพลิเคชั่นที่หลากหลาย มันมีฟังก์ชั่นมากมายสำหรับการทำงานกับสตริงซึ่งreplace()ถ้าเป็นเช่นvar="Hello World"นั้นคุณก็สามารถทำได้var.replace("Hello","Good Morning")

วิธีง่ายๆในการอ่านไฟล์และแทนที่สตริงในนั้นจะเป็นดังนี้:

python -c "import sys;lines=sys.stdin.read();print lines.replace('blue','azure')" < input.txt

อย่างไรก็ตามด้วย Python คุณต้องส่งออกไปยังไฟล์ใหม่ซึ่งคุณสามารถทำได้จากภายในสคริปต์เอง ตัวอย่างเช่นนี่คือตัวอย่างง่ายๆ:

#!/usr/bin/env python
import sys
import os
import tempfile

tmp=tempfile.mkstemp()

with open(sys.argv[1]) as fd1, open(tmp[1],'w') as fd2:
    for line in fd1:
        line = line.replace('blue','azure')
        fd2.write(line)

os.rename(tmp[1],sys.argv[1])

สคริปต์นี้จะถูกเรียกด้วยinput.txtเป็นอาร์กิวเมนต์บรรทัดคำสั่ง คำสั่งที่แน่นอนในการเรียกใช้สคริปต์หลามที่มีอาร์กิวเมนต์บรรทัดคำสั่งจะเป็น

 $ ./myscript.py input.txt

หรือ

$ python ./myscript.py input.txt

แน่นอนตรวจสอบให้แน่ใจว่า./myscript.pyอยู่ในไดเรกทอรีการทำงานปัจจุบันของคุณและสำหรับวิธีแรกตรวจสอบให้แน่ใจว่าได้ตั้งค่าปฏิบัติการไว้ด้วยchmod +x ./myscript.py

Python สามารถมีการแสดงออกปกติโดยเฉพาะอย่างยิ่งมีreโมดูลซึ่งมีre.sub()ฟังก์ชั่นซึ่งสามารถใช้สำหรับการเปลี่ยนขั้นสูงเพิ่มเติม


1
รวบรวมที่ดี! อีกวิธีที่เป็นไปได้ที่ไม่ได้กล่าวถึงที่นี่คือการใช้trคำสั่งในยูนิกซ์
Tapajit Dey

1
@TapajitDey ใช่tr เป็นอีกหนึ่งเครื่องมือที่ดี แต่ทราบว่ามันเป็นสำหรับการเปลี่ยนชุดของตัวอักษร (ตัวอย่างเช่นtr abc cdeจะแปลaไปc, bไปdมันเป็นบิตที่แตกต่างกันจากการแทนที่ทั้งคำเช่นเดียวกับ. sedหรือpython
Sergiy Kolodyazhnyy

22

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

ex -s -c '%s/OLD/NEW/g|x' file
  1. % เลือกทุกบรรทัด

  2. s แทน

  3. g แทนที่อินสแตนซ์ทั้งหมดในแต่ละบรรทัด

  4. x เขียนหากมีการเปลี่ยนแปลง (มี) และออก


21

ผ่านคำสั่ง gsub ของ awk

awk '{gsub(/pattern/,"replacement")}' file

ตัวอย่าง:

awk '{gsub(/1/,"0");}' file

ในตัวอย่างข้างต้น 1 ทั้งหมดจะถูกแทนที่ด้วย 0 โดยไม่คำนึงถึงคอลัมน์ที่อยู่


หากคุณต้องการแทนที่คอลัมน์ใดคอลัมน์หนึ่งให้ทำเช่นนี้

awk '{gsub(/pattern/,"replacement",column_number)}' file

ตัวอย่าง:

awk '{gsub(/1/,"0",$1);}' file

มันแทนที่ 1 ด้วย 0 ในคอลัมน์แรกเท่านั้น

ผ่าน Perl

$ echo 'foo' | perl -pe 's/foo/bar/g'
bar

ฉันใช้นี้บน MacOS ขั้วและมันก็ไม่ได้ทำอะไร ...
จิม

ทดสอบบน Alpine Linux (ใน Docker container) และไม่มีเอาต์พุต
Salathiel Genèse

@ SalathielGenèseคุณพยายามทำอะไรให้สำเร็จ
Avinash Raj

ฉันกำลังดูไฟล์ที่inotifywaitอยู่ภายใต้shenv และข้อมูลการรายงานในรูปแบบ CSV (เนื่องจากรูปแบบที่กำหนดเองเป็นรถบั๊กกี้) ฉันคิดแล้วว่าไม่มีวิธีง่ายๆในการจัดการเอกสาร CSV ในเชลล์สคริปต์ ... และฉันต้องการให้มันเบามาก ดังนั้นฉันจึงเริ่มสคริปต์ง่ายๆในการแยกวิเคราะห์และรายงาน CSV ฉันอ่านข้อมูลจำเพาะของ CSV และสังเกตว่ามันมีรายละเอียดมากกว่าที่ฉันคาดไว้และรองรับค่าหลายบรรทัดในเครื่องหมายคำพูดคู่ ฉันพึ่งโทsedเค็น แต่ในไม่ช้าก็ตระหนักว่าแม้แต่สิ่งที่sedเรียกว่า multilines ก็มีมากถึงสองบรรทัด ถ้าหากหนึ่งในค่า CSV ของฉันครอบคลุมมากกว่าสองบรรทัดล่ะ
Salathiel Genèse

ดีกว่าที่จะถามปัญหาของคุณเป็นคำถาม
Avinash Raj

8

sedเป็นs tream ed itorซึ่งคุณสามารถใช้|( ไพพ์ ) เพื่อส่งสตรีมมาตรฐาน (STDIN และ STDOUT โดยเฉพาะ) ผ่านsedและปรับเปลี่ยนให้เป็นแบบโปรแกรมได้ทันทีทำให้เป็นเครื่องมือที่สะดวกในประเพณีปรัชญา Unix; แต่สามารถแก้ไขไฟล์ได้โดยตรงเช่นกันโดยใช้-iพารามิเตอร์ที่กล่าวถึงด้านล่าง
พิจารณาสิ่งต่อไปนี้ :

sed -i -e 's/few/asd/g' hello.txt

s/จะใช้ในการs ubstitute การแสดงออกพบfewกับasd:

ไม่กี่คนที่กล้าหาญ


asd ความกล้าหาญ

/gย่อมาจาก "ทั่วโลก" หมายถึงการทำเช่นนี้เพื่อทั้งบรรทัด หากคุณออกจาก/g(ด้วยs/few/asd/จะต้องมีสามเครื่องหมายทับไม่ว่าจะเกิดอะไรขึ้น) และfewปรากฏสองครั้งในบรรทัดเดียวกันเฉพาะอันแรกเท่านั้นที่fewเปลี่ยนเป็นasd:

ผู้ชายไม่กี่ผู้หญิงไม่กี่คนที่กล้าหาญ


ผู้ชาย asd ผู้หญิงไม่กี่คนที่กล้าหาญ

สิ่งนี้มีประโยชน์ในบางสถานการณ์เช่นการแก้ไขอักขระพิเศษที่จุดเริ่มต้นของบรรทัด (ตัวอย่างเช่นการแทนที่สัญลักษณ์ที่มากกว่าคนบางคนใช้เพื่ออ้างถึงเนื้อหาก่อนหน้าในหัวข้ออีเมลด้วยแท็บแนวนอนในขณะที่ปล่อยความไม่เท่าเทียมกันเชิงพีชคณิต แตะต้อง) แต่ในตัวอย่างของคุณที่คุณระบุว่าทุกที่ เกิดขึ้นมันควรจะเปลี่ยนให้แน่ใจว่าคุณได้ว่าfew/g

สองตัวเลือก (ธง) ต่อไปนี้จะรวมกันเป็นหนึ่ง-ie:

-iตัวเลือกที่จะใช้ในการแก้ไขฉัน n hello.txtวางบนไฟล์

-eตัวเลือกบ่งชี้ว่าe xpression / คำสั่งให้ทำงานในกรณีs/นี้

หมายเหตุ: สิ่งสำคัญคือคุณ-i -eต้องใช้ในการค้นหา / แทนที่ หากคุณทำเช่น-ieนั้นคุณจะสร้างสำเนาสำรองของทุกไฟล์ด้วยตัวอักษร 'e' ต่อท้าย


2

คุณสามารถทำสิ่งนี้:

locate <part of filaname to locate> | xargs sed -i -e "s/<Old text>/<new text>/g" 

ตัวอย่าง: เพื่อแทนที่เหตุการณ์ทั้งหมด [logdir ',' '(โดยไม่มี []) ด้วย [logdir', os.getcwd ()] ในไฟล์ทั้งหมดที่เป็นผลลัพธ์ของคำสั่งค้นหาให้ทำ:

EX1:

locate tensorboard/program.py | xargs sed -i -e "s/old_text/NewText/g"

EX2:

locate tensorboard/program.py | xargs sed -i -e "s/logdir', ''/logdir', os.getcwd()/g"

โดยที่ [tensorboard / program.py] เป็นไฟล์ที่จะค้นหา


สวัสดี การเลือกสตริง ( logdir', ''-> /logdir', os.getcwd()) ทำให้คำตอบนี้ยากที่จะแยกวิเคราะห์ นอกจากนี้ควรระบุว่าคำตอบของคุณตั้งอยู่ที่ไฟล์ที่จะใช้ sed เนื่องจากไฟล์นั้นไม่ใช่ส่วนหนึ่งของคำถาม
mwfearnley

สวัสดีคำตอบนี้เป็นทั้งการค้นหาและแทนที่ทั้งหมดหากพบ <ข้อความเก่า> ในไฟล์
เหงียนTuấn Anh

ฉันเลือกคำตอบนี้สำหรับทุกคนที่ใช้ tenorboard ใน keras ผู้ที่ต้องการเปลี่ยนคำสั่งจาก: tensorboard --logdir = '/ path / to / log / folder /' เพื่อใช้: tenorboard เท่านั้นเมื่ออยู่ในโฟลเดอร์ logs มันสะดวกมาก
NguyễnTuấn Anh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.