Cách dễ nhất để thêm một chuỗi vào đầu mỗi dòng của tệp từ dòng lệnh là gì?


8

Tôi đang tìm cách để thêm một số chuỗi vào đầu mỗi dòng (cùng một chuỗi cho mỗi dòng). Không phải thứ gì đó có thể tùy chỉnh mà là thứ gì đó sẽ dễ nhớ và có sẵn trên mọi nền tảng tuân thủ POSIX (cũng như mọi vỏ).

Câu trả lời:


8

Bạn có thể sử dụng sed:

sed -i 's/^/your_string /' your_file

Nhờ ý kiến ​​của Stephane và Marco, lưu ý rằng -itùy chọn không phải là POSIX. Một cách POSIX để làm những điều trên sẽ là

sed 's/^/your_string /' your_file > tmp_copy && mv tmp_copy your_file

hoặc perl:

perl -pi -e 's/^/your_string /' your_file

Giải trình

Cả hai lệnh thực hiện thay thế regex, thay thế bắt đầu của một dòng ( ^) bằng chuỗi mong muốn của bạn. Công -itắc trong cả hai lệnh đảm bảo tệp được chỉnh sửa tại chỗ (nghĩa là các thay đổi được phản ánh trong tệp thay vì được in ra thiết bị xuất chuẩn).

sedphải có sẵn trên bất kỳ HĐH tuân thủ POSIX nào và perlphải có sẵn trên hầu hết các Unice hiện đại ngoại trừ những ứng dụng đã trải qua nỗ lực loại bỏ nó.


1
Chỉnh sửa nhỏ: Công -itắc không chỉnh sửa tệp tại chỗ. Nó tạo một tệp mới và ghi đè lên tệp gốc sau khi hoàn thành (bằng chứng: thay đổi inode). Không có nhiều công cụ thực sự chỉnh sửa tại chỗ, đây là một hoạt động nguy hiểm. Hơn nữa, vì bạn đề cập đến POSIX, công -itắc không bắt buộc phải tương thích với POSIX sed, đây là một tính năng của một số triển khai cụ thể.
Marco

2
sed -ikhông phải là POSIX. Đó là GNU. FreeBSD sedcó một tùy chọn tương tự, nhưng bạn cần sed -i ''ở đó.
Stéphane Chazelas

@Marco Tôi biết rằng -itạo một bản sao tạm thời (đó là lý do tại sao tôi nói các thay đổi được phản ánh trong tệp gốc); Tôi có nghĩa là bạn có được ngữ nghĩa tương tự như thay thế tại chỗ. Vui lòng kiểm tra xem câu trả lời được cập nhật có tuân thủ POSIX không.
Joseph R.

Nói đúng ra, những thay đổi được phản ánh trong một tệp mới có cùng tên với bản gốc.
Keith Thompson

1
Tôi thường sử dụng $$(id quá trình của shell hiện tại) như một phần của tên tệp tạm thời; nó tránh được nỗ lực nghĩ về một cái tên duy nhất được bảo đảm mỗi lần:command filename > filename.$$ && mv filename.$$ filename
Keith Thompson

14
:|paste -d'foo ' - - - - input > output

(đùa thôi, mặc dù có lẽ bạn sẽ thấy nó là giải pháp nhanh nhất được đăng ở đây: -b).

Cách thức kinh điển là:

sed 's/^/foo /' < input > output

Tuy nhiên, nó không dễ dàng thích nghi với các chuỗi tùy ý. Ví dụ,

sed "s/^/$var /"

Chỉ hoạt động nếu $varkhông chứa, &, \, /cũng không ký tự xuống dòng.

Về vấn đề đó,

export var
awk '{print ENVIRON["var"], $0}'

hoặc là

perl -pe '$_="$ENV{var} $_"'

sẽ làm việc tốt hơn


đó là một điều thú vị ...: P
Rahul Patil

4

Tôi trình bày một giải pháp bằng cách sử dụng awktrước chuỗi Foov.

awk '{ print "foo", $0; }' input > output

awklà đa nền tảng và có sẵn trên bất kỳ hệ thống POSIX nào. Nó không thực hiện chỉnh sửa tại chỗ. Nếu bạn muốn chỉnh sửa một tệp mà không tạo tệp thứ hai, bạn sẽ phải sử dụng tệp tạm thời. Xem sedcâu trả lời của Joseph , nó hiển thị cú pháp. Một cách hack khác là sử dụng cú pháp sau, về cơ bản là tạo một tệp tạm thời có cùng tên tệp với tệp gốc.

{ rm file; awk '{ print "foo", $0 }' > file; } < file

reducto# wc -l foo`914 foo` reducto# { rm foo ; awk '{ print "prepend" , $0 }' > foo } < foo >Điều này dường như không hoạt động. Tôi đã cố gắng vì việc chuyển hướng sang bản gốc khiến tôi lo lắng, nhưng nó thậm chí sẽ không bắt đầu.
kurtm

1
Ví dụ này sẽ hoạt động nếu nó sử dụng dấu ngoặc đơn cho bên ngoài thay vì dấu ngoặc nhọn.
kurtm

4

Bạn có thể tránh các vấn đề về chỉnh sửa tại chỗ với các công cụ truyền phát bằng cách sử dụng một công cụ thường thực hiện chỉnh sửa tại chỗ - một trình chỉnh sửa!

ex sample.txt -c "%s/^/foo /" -c wq

Có một lợi thế nữa là các lệnh này dễ dàng và rõ ràng đối với bất kỳ ai thành thạo trong một trình soạn thảo thực sự.


2

Bạn có thể sử dụng perlđể làm điều này:

$ perl -pi -e 's/^/mystring /' afile.txt

Thí dụ

Tạo một tệp mẫu.

$ seq 5 > afile.txt

$ cat afile.txt
1
2
3
4
5

Chạy lệnh trên:

$ perl -pi -e 's/^/mystring /' afile.txt

$ cat afile.txt
mystring 1
mystring 2
mystring 3
mystring 4
mystring 5

Perl dường như là phổ quát ngày nay, nhưng trong một thời gian dài thì không. Và tôi cá là có một vài biến thể UNIX hiếm hoi ngoài kia kiên quyết từ chối không có perl như một phần của cơ sở. Một cái gì đó để nhận thức được.
kurtm

@kurtm xem các cuộc thảo luận ở đây . Rõ ràng, AIX không có Perl theo mặc định và cũng không có các hệ thống nhúng.
terdon

2
@DavidScellence - nó đủ phổ biến. Q được gắn thẻ với Bash nên tôi thấy cực kỳ khó tưởng tượng một hệ thống có Bash nhưng không phải Perl. Ở bất cứ giá nào, đây là một trong 5 câu trả lời, một số câu trả lời khác cho thấy cách sử dụng sed, tôi đã chỉ ra cách sử dụng Perl .... không tìm kiếm một cuộc chiến thần thánh về vấn đề này.
slm

1
@DavidScellence Rõ ràng chỉ có OpenBSD. Tôi đoán tôi đã đưa ra giả định vì những người mở có xu hướng bảo thủ về những gì họ cho phép trong cơ sở. OpenBSD chắc chắn có nó trong cơ sở.
kurtm

1
@slm: " Tôi thấy cực kỳ khó tưởng tượng một hệ thống có Bash nhưng không phải Perl ". Tôi có một số hệ thống như vậy ngồi trên bàn của tôi. (Chúng tình cờ là các hệ thống nhúng.)
Keith Thompson

1

Đơn giản chỉ cần sử dụng Bash

 while IFS= read -r line; do echo "foo" "${line}" ; done  < input > Output

Sử dụng Python

python -c "import sys; print 'foo '.join([ l for l in sys.stdin.readlines() ])" < input > Output

Nếu bạn muốn chỉnh sửa tại chỗ

import fileinput
import sys

for line in fileinput.input(['inputfile'], inplace=True):
    sys.stdout.write('foo {l}'.format(l=line))

Liên kết tham khảo


Tại sao nó hoạt động nhanh hơn awk?
Rahul Patil

1
Nó chỉ hoạt động nhanh hơn awktrên các tệp rất nhỏ. Các hành vi khác nhau trên các triển khai tiếng vang và nó loại bỏ các khoảng trống hàng đầu và dấu và xử lý dấu gạch chéo ngược đặc biệt.
Stéphane Chazelas

@StephaneChazelas Có. bạn hoàn toàn chính xác 100% vừa được kiểm tra ... paste.ubfox.com/6210934
Rahul Patil

prefix () { while IFS= read -r REPLY; do printf "%s%s\n" "$1" "$REPLY"; done; }nên được chính xác hơn.
Matt

1
Tại sao {}? Tôi nghĩ rằng @Matt đã gợi ý bạn biến nó thành một hàm được đặt tên, điểm nào {}không có tên hàm?
terdon

-1

Hoặc bạn có thể làm như sau:

vi filename.txt

Esc(để đảm bảo bạn đang ở NORMALchế độ), rồi nhập lệnh sau:

:1,$ s/^/mystring

Lưu ý rằng vì người dùng đang hỏi về mọi dòng của tệp, bạn có thể thay thế 1,$ bằng cách đơn giản %. Điều này làm cho lệnh :%s/^/string/.
HalosGhost
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.