2012-06-21 39 views
87

Tôi có một tình huống mà tôi muốn tập lệnh bash để thay thế toàn bộ dòng trong tệp. Số dòng luôn giống nhau, do đó có thể là một biến được mã hóa cứng.Làm thế nào để thay thế toàn bộ dòng trong một tệp văn bản

Tôi không cố gắng thay thế một số chuỗi con trong dòng đó, tôi chỉ muốn thay thế dòng đó hoàn toàn bằng một dòng mới.

Có phương pháp bash nào để thực hiện việc này (hay một thứ đơn giản nào đó có thể được ném vào tập lệnh .sh).

Trả lời

123

Not the greatest, nhưng điều này sẽ làm việc:

sed -i 'Ns/.*/replacement-line/' file.txt 

nơi N nên được thay thế bằng số dòng mục tiêu của bạn. Điều này sẽ thay thế dòng trong tệp gốc. Để lưu văn bản sửa đổi trong một tập tin khác nhau, thả các tùy chọn -i:

sed 'Ns/.*/replacement-line/' file.txt > new_file.txt 
+0

Có cách nào để làm cho sed sửa đổi các tập tin trong câu hỏi thay vì bán phá giá để sàng lọc? – user788171

+0

Tôi bây giờ nhấn với sed: tùy chọn bất hợp pháp - tôi có một sửa chữa cho điều này? – user788171

+0

cài đặt cổng sudo sed? bạn đang dùng mac à? nếu vậy, chỉ cần sử dụng phiên bản * nix –

14

Giả sử bạn muốn thay thế dòng 4 với nội dung "khác biệt". Bạn có thể sử dụng AWK như sau:

awk '{ if (NR == 4) print "different"; else print $0}' input_file.txt > output_file.txt 

AWK xem đầu vào là "bản ghi" được chia thành "trường". Theo mặc định, một dòng là một bản ghi. NR là số bản ghi được xem. $0 đại diện cho bản ghi hoàn chỉnh hiện tại (trong khi $1 là trường đầu tiên từ bản ghi và vân vân; theo mặc định các trường là các từ trong dòng).

Vì vậy, nếu số dòng hiện tại là 4, in chuỗi "khác" nhưng nếu không in dòng không thay đổi.

Trong AWK, mã chương trình được đính kèm trong { } chạy một lần trên mỗi bản ghi đầu vào.

Bạn cần báo giá chương trình AWK trong một dấu nháy đơn để ngăn trình cố giải thích những thứ như $0.

EDIT: Một chương trình AWK ngắn hơn và thanh lịch hơn từ @chepner trong các ý kiến ​​dưới đây:

awk 'NR==4 {$0="different"} { print }' input_file.txt 

Chỉ cho kỷ lục (ví dụ: dòng) số 4, thay thế toàn bộ kỷ lục với chuỗi "khác nhau". Sau đó cho mỗi bản ghi đầu vào, in bản ghi.

Rõ ràng kỹ năng AWK của tôi đã bị gỉ! Cảm ơn bạn, @chepner.

EDIT: và xem thêm một phiên bản thậm chí ngắn hơn từ @Dennis Williamson:

awk 'NR==4 {$0="different"} 1' input_file.txt 

Làm thế nào các công trình này được giải thích trong các ý kiến: các 1 luôn đánh giá đúng, vì vậy khối mã liên quan luôn luôn chạy. Nhưng không có khối mã liên quan, có nghĩa là AWK làm hành động mặc định của nó chỉ in toàn bộ dòng. AWK được thiết kế để cho phép các chương trình terse như thế này.

+2

Ngắn hơn một chút:' awk 'NR == 4 {$ 0 = "khác"} { print} 'input_file.txt'. – chepner

+1

@chepner: A little ngắn hơn: 'awk 'NR == 4 {$ 0 = "khác nhau"} 1' input_file.txt' –

+0

@DennisWilliamson, tôi thậm chí không biết làm thế nào mà làm việc! Chữ "1' có dấu gì? (Lưu ý: Tôi đã thử nghiệm nó và nó thực sự làm việc! Tôi chỉ không hiểu làm thế nào.) – steveha

5

trong bash, thay thế N, M bằng số dòng và xxx yyy bởi những gì bạn muốn

i=1 
while read line;do 
    if((i==N));then 
    echo 'xxx' 
    elif((i==M));then 
    echo 'yyy' 
    else 
    echo "$line" 
    fi 
    ((i++)) 
done < orig-file > new-file 

EDIT

Trong thực tế trong giải pháp này có một số vấn đề, với các nhân vật "\ 0" "\ t" và "\"

"\ t", có thể được giải quyết bằng cách đặt IFS = trước khi đọc: "\", ở cuối dòng với -r

IFS= read -r line 

nhưng đối với "\ 0", biến là cắt ngắn, không có là một giải pháp trong bash tinh khiết: Assign string containing null-character (\0) to a variable in Bash Nhưng trong tập tin văn bản bình thường không có nhân vật nul \ 0

perl sẽ là một lựa chọn tốt hơn

perl -ne 'if($.==N){print"xxx\n"}elsif($.==M){print"yyy\n"}else{print}' < orig-file > new-file 
+0

Tôi thậm chí không nghĩ đến việc thử một giải pháp BASH thuần túy! – steveha

9

với tập tin thử nghiệm này (test.txt)

Lorem ipsum dolor sit amet, 
consectetur adipiscing elit. 
Duis eu diam non tortor laoreet 
bibendum vitae et tellus. 

lệnh sau đây sẽ thay thế dòng đầu tiên "xuống dòng text"

012.
$ sed '1 c\ 
> newline text' test.txt 

Kết quả:

newline text 
consectetur adipiscing elit. 
Duis eu diam non tortor laoreet 
bibendum vitae et tellus. 
hơn

thông tin có thể được tìm thấy ở đây

http://www.thegeekstuff.com/2009/11/unix-sed-tutorial-append-insert-replace-and-count-file-lines/

+1

Đây phải là câu trả lời đúng. Cờ c thực hiện chính xác những gì được yêu cầu (thay thế một dòng được đánh số với văn bản đã cho). – adelphus

+0

cú pháp thay thế với sed điều đó không có tiếng vang các tập tin trên thiết bị xuất chuẩn: https://stackoverflow.com/a/13438118/4669135 –

38

Tôi thực sự sử dụng kịch bản này để thay thế một dòng mã trong file cron trên các máy chủ UNIX của công ty chúng tôi một lát trở lại. Chúng tôi thực hiện nó như là shell script bình thường và không có vấn đề:

#Create temporary file with new line in place 
cat /dir/file | sed -e "s/the_original_line/the_new_line/" > /dir/temp_file 
#Copy the new file over the original file 
mv /dir/temp_file /dir/file 

này không đi theo số dòng, nhưng bạn có thể dễ dàng chuyển sang một hệ thống dựa trên số dòng bằng cách đặt số dòng trước s/ và đặt một ký tự đại diện thay cho the_original_line.

+13

sử dụng vô dụng của mèo: 'sed -e "s /.../.../"/ dir/file>/dir/temp_file' – chepner

+16

Vô dụng cho trình thông dịch/biên dịch có thể, nhưng không phải cho một người đọc nó. @ Mã của Kyle đọc độc đáo từ trái sang phải; thành ngữ bạn sử dụng IMO không, do thực tế là động từ trước danh từ. –

+0

Có cách nào để kết hợp hai dòng này, ví dụ như một cái gì đó như, 'sed -e 's /.../.../"/dir/file>/dir/file' –

1

Câu trả lời hay từ Chepner. Nó làm việc cho tôi trong bash Shell.

# To update/replace the new line string value with the exiting line of the file 
MyFile=/tmp/ps_checkdb.flag 

`sed -i "${index}s/.*/${newLine}/" $MyFile` 

đây
index - Line không
newLine - dòng chuỗi mới mà chúng tôi muốn thay thế.


Tương tự như mã dưới đây được sử dụng để đọc một dòng cụ thể trong tệp. Điều này sẽ không ảnh hưởng đến tệp thực tế.

LineString=`sed "$index!d" $MyFile` 

đây
!d - sẽ xóa các dòng khác so với dòng không $index Vì vậy, chúng tôi sẽ nhận được đầu ra như chuỗi dòng không $index trong file.

+0

nhưng nó bash của tôi tại sao kết quả chỉ hiển thị '$ {newline}'? – sikisis

1

# Replace the line of the given line number with the given replacement in the given file. 
 
function replace-line-in-file() { 
 
    local file="$1" 
 
    local line_num="$2" 
 
    local replacement="$3" 
 
    
 
    # Escape backslash, forward slash and ampersand for use as a sed replacement. 
 
    replacement_escaped=$(echo "$replacement" | sed -e 's/[\/&]/\\&/g') 
 
    
 
    sed -i "${line_num}s/.*/$replacement_escaped/" "$file" 
 
}

-1

Bạn thậm chí có thể vượt qua các tham số cho lệnh sed:

test.sh

#!/bin/bash 
echo "-> start" 
for i in $(seq 5); do 
    # passing parameters to sed 
    j=$(($i+3)) 
    sed -i "${j}s/.*/replaced by '$i'!/" output.dat 
done 
echo "-> finished" 
exit 

orignial output.dat:

a 
b 
c 
d 
e 
f 
g 
h 
i 
j 

Thi ./test.sh đưa ra mới output.dat

a 
b 
c 
replaced by '1'! 
replaced by '2'! 
replaced by '3'! 
replaced by '4'! 
replaced by '5'! 
i 
j 
+0

tại sao bạn cần một vòng lặp cho ví dụ này, chỉ làm xáo trộn giải pháp? '' line = 5; sed -i "$ {line} s /.*/ được thay thế bởi '$ i'! /" output.dat'' – Rob

Các vấn đề liên quan