Có cách nào khác đơn giản để nối dòng vào cuối tệp ngoài `>>` không?


21

Gần đây tôi đang lặp lại những câu ngắn vào một tree_holetập tin.

Tôi đã sử dụng echo 'something' >> tree_holeđể làm công việc này.

Nhưng tôi luôn lo lắng về những gì nếu tôi nhập sai >thay vì >>, vì tôi thường xuyên làm điều này.

Vì vậy, tôi đã tạo ra một bash toàn cầu của riêng mình trong bashrc:

function th { echo "$1" >> /Users/zen1/zen/pythonstudy/tree_hole; }
export -f th

Nhưng tôi tự hỏi nếu có một cách đơn giản khác để nối các dòng vào cuối tập tin. Bởi vì tôi có thể cần phải sử dụng nó thường xuyên trong những dịp khác.

Có cái nào không?


9
Bạn sẽ không quên bạn đang sử dụng công việc mỗi khi bạn vào> chứ? Khi tôi đã có một bí danh rm="rm -i"và trong một môi trường khác đã viết rm *chờ đợi các câu hỏi xác nhận. Bạn đang học thói quen nguy hiểm!
Walter A

9
@WalterA er, "cách giải quyết" của anh ấy không cho phép anh ấy gõ> thay vì >>, anh ấy chỉ chạy "th some_sentence", không làm gì nếu bí danh không được xác định.
Random832

1
@ Ranom832 chính xác cho công việc của mình. Cảnh báo là cho một "giải pháp" như noclobber. Khi anh ta sử dụng thứ gì đó như noclobber trong vỏ bình thường, anh ta có thể sử dụng> khi anh ta tạm thời root và muốn nối thêm thứ gì đó.
Walter A

7
@ Random832 & WalterA Tôi thường không nói gì về điều này khi tôi nhìn thấy nó, nhưng tôi nghĩ rằng thỉnh thoảng có thể một thông báo thân thiện có thể hữu ích. Hồ sơ người dùng của Zen không có nhiều chi tiết, vì vậy tôi không chắc liệu bạn có thực sự biết rằng "cách giải quyết" của anh ấy là hình thức chính xác hay không. Có lẽ bạn nên nói "workaround" của họ hoặc "workaround" của OP . Có lẽ bạn biết Zen cá nhân và do đó bạn biết rằng anh ấy là chính xác, trong trường hợp đó, xin vui lòng bỏ qua tiếng ồn. Không phải là một vấn đề lớn, tôi chỉ đề cập đến nó bởi vì tôi biết tôi sẽ không đánh giá cao nó nếu bạn đã sử dụng hình thức đó để nói về tôi.
Celada

1
@Zen, Bạn đã viết rằng bạn lo lắng nhập sai> thay vì >>. Kế hoạch của Celada sẽ loại bỏ các rủi ro trong môi trường của bạn và là một giải pháp tốt cho bạn. Khi bạn đang giúp hàng xóm của mình (người không có noclobber hoặc đang sử dụng ksh) và bạn đã mất sự chú ý của mình cho một hoặc hai> ký tự, bạn có thể vô tình ghi đè lên một trong các tệp của anh ấy. Vì vậy, bất cứ khi nào bạn nhận được cảnh báo noclobber trong môi trường của riêng bạn, cảm ơn Chúa hoặc Celada, hãy nói với chính mình: Ohh, hãy cẩn thận!, Lắc đầu và chờ hai giây.
Walter A

Câu trả lời:


47

Đặt noclobbertùy chọn của shell :

bash-3.2$ set -o noclobber
bash-3.2$ echo hello >foo
bash-3.2$ echo hello >foo
bash: foo: cannot overwrite existing file
bash-3.2$ 

3
Đây là câu trả lời dứt khoát. Lưu ý rằng bạn vẫn có thể ghi đè lên tệp nếu bạn ép buộc >|. zshcho phép hành vi này theo mặc định.
orion

1
@orion Làm thế nào để bạn en / vô hiệu hóa nó trong zsh? Tôi không nhớ rõ việc vô hiệu hóa nó, nhưng ghi đè hoạt động tốt trên zsh của tôi.
muru

2
Đó là setopt noclobbersetopt clobber. Có vẻ như nó không chính xác là "mặc định", nó phụ thuộc vào các tệp cấu hình được gửi cùng với bản phân phối của bạn.
orion

@muru nên làm việc với set [+-]Cbất kỳ lớp vỏ hiện đại nào
mikeerv

3
@Zen set +o noclobbertrong bash, hoặc set +C.
Ruslan

7

Nếu bạn lo lắng tệp của bạn sẽ bị hỏng bởi >toán tử, bạn có thể thay đổi thuộc tính tệp của mình thành chỉ nối thêm:
Trong hệ thống tệp ext2 / ext3 / ext4 : chattr +a file.txt
Trong hệ thống tệp XFS :echo chattr +a | xfs_io file.txt

Và nếu bạn muốn có một chức năng, tôi đã tạo một chức năng cho chính mình (Tôi đã sử dụng nó trong tệp dịch vụ để ghi nhật ký đầu ra), Bạn có thể thay đổi nó cho mục đích của mình:

# This function redirect logs to file or terminal or both!
#@ USAGE: log option data
# To the file     -f file
# To the terminal -t
function log(){
        read -r data       # Read data from pipe line

        [[ -z ${indata} ]] && return 1    # Return 1 if data is null

        # Log to /var/log/messages
        logger -i -t SOFTWARE ${data}

        # While loop for traveling on the arguments
        while [[ ! -z "$*" ]]; do
                case "$1" in
                        -t)
                                # Writting data to the terminal
                                printf "%s\n" "${data}"
                                ;;
                        -f) 
                                # Writting (appending) data to given log file address
                                fileadd=$2
                                printf "%s %s\n" "[$(date +"%D %T")] ${data}" >> ${fileadd}
                                ;;
                        *)
                                ;;
                esac
                shift           # Shifting arguments
        done
}

2
Có một vài vấn đề với kịch bản này. 1) Nói chung, bạn nên đặt dấu ngoặc kép xung quanh các mở rộng tham số (nội dung bắt đầu bằng a $) để ngăn chặn quá trình tạo khối, tách từ và các vấn đề khoảng trắng liên quan. Ứng dụng ShellCheck trực tuyến có thể nắm bắt được vấn đề này và nhiều vấn đề khác trong tập lệnh bash. Trên một lưu ý liên quan "$@"nhiều an toàn hơn $*.
PM 2Ring

3
2) Thông thường bạn nên gọi readlệnh với -rtùy chọn để ngăn chặn bất kỳ dấu gạch chéo ngược nào trong đầu vào thoát khỏi ký tự sau. 3) Thông thường trong các tập lệnh bash sử dụng chữ thường cho tên biến tập lệnh vì TẤT CẢ TRƯỜNG HỢP được sử dụng cho các biến hệ thống. Vì vậy, nếu bạn sử dụng chữ hoa cho các biến của riêng mình, bạn sẽ nhầm lẫn những người đọc mã của bạn và bạn có thể vô tình ghi đè một biến hệ thống mà bạn muốn sử dụng sau này trong tập lệnh. Và nếu bạn nguồn kịch bản, nó sẽ clobber các biến cho các lệnh tiếp theo.
PM 2Ring

3
4) thuận echotiện cho việc in các chuỗi cố định, nhưng nó có thể thực hiện những điều không mong muốn với dữ liệu tùy ý, đặc biệt là trên các hệ thống GNU. Đó là xa an toàn hơn để sử dụng printf. Xem unix.stackexchange.com/questions/65804/ trên để biết thêm thông tin, đặc biệt là câu trả lời của Stéphane Chazelas.
PM 2Ring

3
@PM 2Ring, Hôm nay tôi học được nhiều điều từ bạn, Cảm ơn rất nhiều .. Tôi sẽ sửa chúng sớm nhất có thể.
Sepahrad Salour

1
Làm tốt lắm, Sepahrad!
PM 2Ring

3

Sử dụng teevới tùy chọn chắp thêm:

foo | tee -a some-file
# or
tee -a some-file <<EOF
blah blah
EOF
# or 
tee -a some-file <<<"blah blah"

5
Ý tưởng hay, +1, nhưng tôi tưởng tượng rằng nếu OP lo lắng về việc quên một >nhân vật thì họ có thể lo lắng về việc quên -atùy chọn!
Celada

@Celada Tôi cho là như vậy (nhưng tôi đoán một lỗi đánh máy bị thiếu một lần nhấn phím trong một bộ tổ hợp phím lặp đi lặp lại có nhiều khả năng xảy ra hơn là quên một tùy chọn).
muru

0

nhiều chương trình có thể mở tệp để ghi đè có thể thay thế mở chúng để chắp thêm, ví dụ: gnu dd.

dd conv=notrunc oflag=append of=file

nó có thể đọc stdin hoặc một tệp có tên trong if= tham số thêm 2>/dev/nullđể triệt tiêu số byte.


3
Đó là một ý tưởng tốt ™ để kiểm tra mã của bạn trước khi đăng nó dưới dạng câu trả lời ...
PM 2Ring

1
Khuyến cáo ddlà một ý tưởng tồi. ddkhông đáng tin cậy ghi đầu vào của nó vào đầu ra của nó , không phải khi một trong số chúng không phải là một tập tin hoặc thiết bị chặn thông thường
Gilles 'SO- ngừng trở nên xấu xa'

@gilles, bạn đang trình bày sai thông tin tại liên kết đó, khi số lượng không được chỉ định dd sẽ sao chép tất cả dữ liệu có sẵn, giống như con mèo.
Jasen

-1

Tôi muốn sử dụng một sed(ngay cả với bản sao lưu dự phòng - xem phần mở rộng sau -i):

sed -i.bak '$ a\something' /Users/zen1/zen/pythonstudy/tree_hole

Tại sao tôi không ngạc nhiên ... bạn là một kẻ điên cuồng, Costas. :) (Đó là một lời khen, BTW)
PM 2Ring

@ PM2Ring Vâng, tôi rất nguy hiểm! : P
Costas

Tất nhiên cách làm việc là tạo một bản sao của tệp, thêm văn bản mới vào cuối, sau đó xóa tệp gốc và đổi tên bản sao thành tên gốc. Điều này (1) không hoạt động nếu bạn không có quyền ghi vào thư mục, (2) phá vỡ liên kết và (3) tốn kém tài nguyên nếu tệp lớn. Thật buồn cười là bạn đã đưa ra từ "nguy hiểm"!
G-Man nói 'Phục hồi Monica'

-1

Bạn luôn có thể tìm kiếm thông qua các tập tin theo những cách khác ...

seq 10000000 >f
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
wc -l f; tail f

... đó là trình tự tìm kiếm kỳ lạ in:

10000000
10000001
10000002
10000003
10000004
10000005 f
9999996
9999997
9999998
9999999
10000000
new line!
new line!
new line!
new line!
new line!

Nhưng điều đó hơi ngớ ngẩn.

Một ví dụ hữu ích hơn có thể trông giống như:

 apnd() if    shift
        then  wc -l  >&2
              printf "$@"
        fi    <>"$1" >&0

Bạn có thể gọi nó như:

 apnd /path/to/file          \
      "${printf_fmt_string}" \
       arbitrary list of strings

Và bạn sẽ kết thúc với một số filedòng được viết stderrngay trước khi hành động chắp thêm diễn ra.

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.