ฉันจะค้นหาและแทนที่คำที่ระบุในไฟล์ข้อความโดยใช้บรรทัดคำสั่งได้อย่างไร
ฉันจะค้นหาและแทนที่คำที่ระบุในไฟล์ข้อความโดยใช้บรรทัดคำสั่งได้อย่างไร
คำตอบ:
sed -i 's/original/new/g' file.txt
คำอธิบาย:
sed
= กระแสบรรณาธิการ-i
= in-place (เช่นบันทึกกลับไปที่ไฟล์ต้นฉบับ)สตริงคำสั่ง:
s
= คำสั่งทดแทนoriginal
= นิพจน์ทั่วไปที่อธิบายคำเพื่อแทนที่ (หรือเพียงแค่คำนั้น ๆ )new
= ข้อความที่จะแทนที่ด้วยg
= global (เช่นแทนที่ทั้งหมดและไม่ใช่เพียงแค่การเกิดขึ้นครั้งแรก)file.txt
= ชื่อไฟล์
sed
จะจับคู่ เพิ่มการ-r
ตั้งค่าสถานะถ้าคุณต้องการใช้ REs แบบขยายแทน
/
อักขระเฉพาะที่คุณต้องการจับคู่คุณสามารถใช้อักขระอื่นเป็นตัวคั่น (เช่น's_old/text_new/text_g'
) มิฉะนั้นคุณสามารถใส่\
ก่อนที่$ * . [ \ ^
จะได้รับตัวอักษร
sed -i '.bak' 's/original/new/g' file.txt
ยังสามารถเรียกใช้ด้วยส่วนขยายที่มีความยาวเป็นศูนย์sed -i '' 's/original/new/g' file.txt
ซึ่งจะไม่สร้างการสำรองข้อมูล
มีหลายวิธีในการทำเช่นนี้ หนึ่งคือการใช้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
cat
ในcat file | sed '...'
ไม่จำเป็น sed '...' file
โดยตรงคุณสามารถพูดได้
sed -i'.bak' -e 's/unicorn/fox/g;s/hyper/brown/g' yarly
จะใช้ไฟล์ yarly และทำการเปลี่ยนแปลง 2 อย่างในขณะทำการสำรองข้อมูล การใช้time bash -c "$COMMAND"
เป็นครั้งคราวแสดงให้เห็นว่าเวอร์ชั่นนี้เร็วกว่า ~ 5 เท่า
มีหลายวิธีที่จะทำให้สำเร็จ ขึ้นอยู่กับความซับซ้อนของสิ่งที่เราพยายามทำให้สำเร็จด้วยการแทนที่สตริงและขึ้นอยู่กับเครื่องมือที่ผู้ใช้คุ้นเคยวิธีการบางอย่างอาจเป็นที่ต้องการมากกว่าวิธีอื่น
ในคำตอบนี้ฉันใช้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 ซึ่งเป็นยูทิลิตี้การประมวลผลข้อความค่อนข้างเหมาะสมสำหรับงานดังกล่าว มันสามารถทำได้ง่ายและเปลี่ยนคนมากขึ้นสูงขึ้นอยู่กับการแสดงออกปกติ มันมีสองฟังก์ชั่น: และ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 's/blue/azure/' input.txt
สิ่งที่ดีเกี่ยวกับเครื่องมือนี้ก็คือมันมีการแก้ไขในสถานที่ซึ่งคุณสามารถเปิดใช้งานด้วยการ-i
ตั้งค่าสถานะ
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()
ฟังก์ชั่นซึ่งสามารถใช้สำหรับการเปลี่ยนขั้นสูงเพิ่มเติม
tr
คำสั่งในยูนิกซ์
tr
เป็นอีกหนึ่งเครื่องมือที่ดี แต่ทราบว่ามันเป็นสำหรับการเปลี่ยนชุดของตัวอักษร (ตัวอย่างเช่นtr abc cde
จะแปลa
ไปc
, b
ไปd
มันเป็นบิตที่แตกต่างกันจากการแทนที่ทั้งคำเช่นเดียวกับ. sed
หรือpython
คุณสามารถใช้ Vim ในโหมด Ex:
ex -s -c '%s/OLD/NEW/g|x' file
%
เลือกทุกบรรทัด
s
แทน
g
แทนที่อินสแตนซ์ทั้งหมดในแต่ละบรรทัด
x
เขียนหากมีการเปลี่ยนแปลง (มี) และออก
ผ่านคำสั่ง 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
inotifywait
อยู่ภายใต้sh
env และข้อมูลการรายงานในรูปแบบ CSV (เนื่องจากรูปแบบที่กำหนดเองเป็นรถบั๊กกี้) ฉันคิดแล้วว่าไม่มีวิธีง่ายๆในการจัดการเอกสาร CSV ในเชลล์สคริปต์ ... และฉันต้องการให้มันเบามาก ดังนั้นฉันจึงเริ่มสคริปต์ง่ายๆในการแยกวิเคราะห์และรายงาน CSV ฉันอ่านข้อมูลจำเพาะของ CSV และสังเกตว่ามันมีรายละเอียดมากกว่าที่ฉันคาดไว้และรองรับค่าหลายบรรทัดในเครื่องหมายคำพูดคู่ ฉันพึ่งโทsed
เค็น แต่ในไม่ช้าก็ตระหนักว่าแม้แต่สิ่งที่sed
เรียกว่า multilines ก็มีมากถึงสองบรรทัด ถ้าหากหนึ่งในค่า CSV ของฉันครอบคลุมมากกว่าสองบรรทัดล่ะ
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' ต่อท้าย
คุณสามารถทำสิ่งนี้:
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 เนื่องจากไฟล์นั้นไม่ใช่ส่วนหนึ่งของคำถาม