Có một lệnh Unix để thêm một số dữ liệu chuỗi vào một tệp văn bản không?
Cái gì đó như:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Có một lệnh Unix để thêm một số dữ liệu chuỗi vào một tệp văn bản không?
Cái gì đó như:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Câu trả lời:
sed -i.old '1s;^;to be prepended;' inFile
-i
ghi thay đổi tại chỗ và sao lưu nếu có bất kỳ phần mở rộng nào được đưa ra. (Trong trường hợp này, .old
)1s;^;to be prepended;
thay thế đầu dòng đầu tiên bằng chuỗi thay thế đã cho, sử dụng ;
làm dấu phân cách lệnh.\n
sau khi trả trước; tùy thuộc vào nhu cầu của họ. Giải pháp gọn gàng.
inFile
thư mục bao gồm trong đường dẫn của nó?
\n
. Nên đọc bình luận trước. Chỉ trích.
'1s;^;my-prepended-line\;\n;'
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt
git config --get-regex $arg | sed -r 's/\t{3}/\\n/g';
và điều này gây rối khi nó chuyển đổi \t
và \n
.
echo "to be prepended"$'\n'"$(cat text.txt)"
Tôi ngạc nhiên không ai đề cập đến điều này.
cat <(echo "before") text.txt > newfile.txt
được cho là tự nhiên hơn câu trả lời được chấp nhận (in một cái gì đó và đưa nó vào một lệnh thay thế là phản trực quan từ vựng).
... và đánh cắp những gì ryan đã nói ở trên, với sponge
bạn không cần một tập tin tạm thời:
sudo apt-get install moreutils
<<(echo "to be prepended") < text.txt | sponge text.txt
EDIT: Có vẻ như điều này không hoạt động trong Bourne Shell /bin/sh
Sử dụng chuỗi ở đây - <<<
, bạn có thể làm:
<<< "to be prepended" < text.txt | sponge text.txt
<<(echo "to be prepended") < text.txt
và <<< "to be prepended" < text.txt
công trình không hoạt động trong bash; họ yêu cầu zsh.
Đây là một khả năng:
(echo "to be prepended"; cat text.txt) > newfile.txt
có lẽ bạn sẽ không dễ dàng có được một tập tin trung gian.
Các lựa chọn thay thế (có thể cồng kềnh với thoát vỏ):
sed -i '0,/^/s//to be prepended/' text.txt
cat <(echo "to be prepended") text.txt > newfile.txt
. Nghĩ về nó, tôi không chắc là của tôi có liên quan, vì vậy tôi đăng một câu trả lời riêng.
Điều này sẽ làm việc để tạo thành đầu ra. - có nghĩa là đầu vào tiêu chuẩn, được cung cấp qua đường ống từ tiếng vang.
echo -e "to be prepended \n another line" | cat - text.txt
Để ghi lại tập tin, một tập tin tạm thời là bắt buộc vì không thể quay trở lại tập tin đầu vào.
echo "to be prepended" | cat - text.txt > text.txt.tmp
mv text.txt.tmp text.txt
text.txt
theo yêu cầu, nhưng hiển thị nó trên thiết bị xuất chuẩn. Đầu ra có thể được chuyển sang một tệp khác nếu hoạt động cho OP
Thích câu trả lời của Adam
Chúng ta có thể làm cho nó dễ dàng hơn để sử dụng bọt biển . Bây giờ chúng tôi không cần tạo một tệp tạm thời và đổi tên nó bằng cách
echo -e "to be prepended \n another line" | cat - text.txt | sponge text.txt
Ghi chú:
Làm như vậy có thể có tác dụng phụ không mong muốn, đáng chú ý là có khả năng thay thế một liên kết tượng trưng bằng một tệp thông thường, kết thúc bằng các quyền khác nhau trên tệp và thay đổi ngày tạo (khai sinh) của tệp.
sed -i
, như trong câu trả lời của Hoàng tử John Wesley , ít nhất cũng cố gắng khôi phục các quyền ban đầu, nhưng các hạn chế khác cũng được áp dụng.
Đây là một giải pháp thay thế đơn giản sử dụng một tệp tạm thời (nó tránh đọc toàn bộ tệp đầu vào vào bộ nhớ theo cách mà giải pháp của shime thực hiện):
{ printf 'to be prepended'; cat text.txt; } > tmp.txt && mv tmp.txt text.txt
Sử dụng lệnh nhóm ( { ...; ...; }
) hiệu quả hơn một chút so với sử dụng một subshell ( (...; ...)
), như trong giải pháp của 0xC0000022L .
Những ưu điểm là:
Thật dễ dàng để kiểm soát liệu văn bản mới có nên được thêm trực tiếp vào dòng đầu tiên hay liệu nó có nên được chèn dưới dạng (các) dòng mới hay không (chỉ cần thêm \n
vào printf
đối số).
Không giống như sed
giải pháp, nó hoạt động nếu tệp đầu vào trống ( 0
byte).
Các sed
giải pháp có thể được đơn giản hóa nếu mục đích là để thêm vào trước một hoặc nhiều toàn bộ dây chuyền đến các nội dung hiện có (giả sử các tập tin đầu vào không bị để trống):
sed
's i
chèn chức năng toàn bộ dòng:
Với GNU sed
:
# Prepends 'to be prepended' *followed by a newline*, i.e. inserts a new line.
# To prepend multiple lines, use '\n' as part of the text.
# -i.old creates a backup of the input file with extension '.old'
sed -i.old '1 i\to be prepended' inFile
Một biến thể di động cũng hoạt động với macOS / BSD sed
:
# Prepends 'to be prepended' *followed by a newline*
# To prepend multiple lines, escape the ends of intermediate
# lines with '\'
sed -i.old -e '1 i\
to be prepended' inFile
Lưu ý rằng dòng mới theo nghĩa đen sau khi \
được yêu cầu.
Sử dụng ed
tiện ích POSIX đáng kính :
Ghi chú:
ed
luôn luôn đọc toàn bộ tệp đầu vào vào bộ nhớ.Để thêm trực tiếp vào dòng đầu tiên (như với sed
, điều này sẽ không hoạt động nếu tệp đầu vào hoàn toàn trống ( 0
byte)):
ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
-s
ed
thông điệp trạng thái bị chặn .ed
dưới dạng nhiều dòng ở đây - document ( <<EOF\n...\nEOF
), tức là thông qua stdin ; theo mặc định mở rộng chuỗi được thực hiện trong các tài liệu đó (các biến shell được nội suy); trích dẫn dấu phân cách mở để triệt tiêu điều đó (ví dụ <<'EOF'
:).1
làm cho dòng thứ 1 thành dòng hiện tạis
thực hiện thay thế chuỗi dựa trên regex trên dòng hiện tại, như trong sed
; bạn có thể bao gồm các dòng mới theo nghĩa đen trong văn bản thay thế, nhưng chúng phải được \
ghi chú.w
ghi kết quả trở lại tệp đầu vào (để kiểm tra, thay thế w
bằng ,p
chỉ in kết quả mà không sửa đổi tệp đầu vào).Để thêm một hoặc nhiều dòng :
Như với sed
, i
hàm luôn luôn thêm một dòng mới vào văn bản sẽ được chèn.
ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
0 i
làm cho 0
(phần đầu của tệp) dòng hiện tại và bắt đầu chế độ chèn ( i
); lưu ý rằng số dòng được 1
dựa trên cơ sở khác ..
dòng riêng của nó.Có lẽ không có gì tích hợp, nhưng bạn có thể tự viết khá dễ dàng, như thế này:
#!/bin/bash
echo -n "$1" > /tmp/tmpfile.$$
cat "$2" >> /tmp/tmpfile.$$
mv /tmp/tmpfile.$$ "$2"
Ít nhất là như thế ...
$$
không đủ cho mã sản xuất (tấn công google symlink); nhưng nó chắc chắn tốt hơn một tên tệp tĩnh.
mktemp
Trong một số trường hợp, văn bản được chuẩn bị trước chỉ có thể có sẵn từ stdin. Sau đó, sự kết hợp này sẽ làm việc.
echo "to be prepended" | cat - text.txt | tee text.txt
Nếu bạn muốn bỏ qua tee
đầu ra, sau đó nối thêm > /dev/null
.
tee
không bị tắc nghẽn text.txt
trước khi cat
đọc nó không? Tôi nghĩ là không - điều này sẽ làm cho giải pháp này trở nên nguy hiểm đối với sức khỏe của tập tin.
lenA=1000000; yes a | head -c $lenA > a.txt; lenB=10000; b=$(yes b | head -c $lenB); echo "$b" | cat - a.txt | tee a.txt > /dev/null
. Nếu lenA
là 1000000 (tệp 1Mb) và lenB
10000 (nạp trước văn bản 10Kb), thì tệp "a.txt" được ghi đè bằng 20Kb chữ cái "b". Điều này là hoàn toàn bị phá vỡ. Bây giờ, nếu bạn sử dụng 1Mb a.txt và văn bản 1Mb để trả trước, tee
đi vào một vòng lặp tạo tệp 7Gb +, tôi đã phải dừng lệnh. Vì vậy, rõ ràng là kết quả không thể đoán trước đối với kích thước lớn. Tôi không có thông tin cho dù nó nên hoạt động trên kích thước nhỏ.
Giải pháp:
printf '%s\n%s' 'text to prepend' "$(cat file.txt)" > file.txt
Lưu ý rằng điều này là an toàn trên tất cả các loại đầu vào, vì không có mở rộng. Ví dụ: nếu bạn muốn trả trước !@#$%^&*()ugly text\n\t\n
, nó sẽ chỉ hoạt động:
printf '%s\n%s' '!@#$%^&*()ugly text\n\t\n' "$(cat file.txt)" > file.txt
Phần cuối cùng còn lại để xem xét là loại bỏ khoảng trắng ở cuối tệp trong khi thay thế lệnh "$(cat file.txt)"
. Tất cả các công việc xung quanh cho điều này là tương đối phức tạp. Nếu bạn muốn duy trì dòng mới ở cuối file.txt, hãy xem điều này: https://stackoverflow.com/a/22607352/1091436
file.txt
nó lớn hơn có thể được gắn vào danh sách đối số printf
.
Một cách khác sử dụng sed
:
sed -i.old '1 {i to be prepended
}' inFile
Nếu dòng được chuẩn bị là multiline:
sed -i.old '1 {i\
to be prepended\
multiline
}' inFile
sed -i '1ito be prepended' inFile
- hoặc nó chỉ được phép cho GNU sed?
sed
, i
lệnh được theo sau bởi dấu gạch chéo ngược và dòng mới và mỗi dòng đầu vào ngoại trừ các kết thúc cuối cùng cũng có dấu gạch chéo ngược. GNU sed
cho phép viết tắt dọc theo dòng bạn hỏi, nhưng chỉ GNU sed
mới làm như vậy. '
Như đã thử nghiệm trong Bash (trong Ubuntu), nếu bắt đầu bằng tệp thử nghiệm qua;
echo "Original Line" > test_file.txt
bạn có thể thực thi;
echo "$(echo "New Line"; cat test_file.txt)" > test_file.txt
hoặc, nếu phiên bản bash quá cũ với $ (), bạn có thể sử dụng backticks;
echo "`echo "New Line"; cat test_file.txt`" > test_file.txt
và nhận các nội dung sau của "test_file.txt";
New Line
Original Line
Không có tập tin trung gian, chỉ bash / echo.
Một giải pháp khá thẳng về phía trước là:
$ echo -e "string\n" $(cat file)
cat
mở rộng tham số trong dấu ngoặc kép là một lý do khá tốt cho một downvote . Mã này đang phân chia nội dung của tệp thành các từ và chuyển từng từ đó thành một đối số riêng biệt echo
. Bạn mất các ranh giới đối số ban đầu, bạn mất các dòng mới / tab / v.v. và các chuỗi như \t
và \n
trong văn bản gốc được thay thế bằng các tab và dòng mới thay vì được giữ nguyên như cũ.
Nếu bạn thích vi / vim, đây có thể là phong cách của bạn hơn.
printf '0i\n%s\n.\nwq\n' prepend-text | ed file
Tôi khuyên bạn nên xác định một chức năng và sau đó nhập và sử dụng chức năng đó khi cần thiết.
prepend_to_file() {
file=$1
text=$2
if ! [[ -f $file ]] then
touch $file
fi
echo "$text" | cat - $file > $file.new
mv -f $file.new $file
}
Sau đó sử dụng nó như vậy:
prepend_to_file test.txt "This is first"
prepend_to_file test.txt "This is second"
Nội dung tệp của bạn sau đó sẽ là:
This is second
This is first
Tôi sắp sử dụng phương pháp này để thực hiện cập nhật nhật ký thay đổi.