2012-01-13 15 views
5

Tôi gặp vấn đề thực sự lạ với/bin/bash và tập lệnh sử dụng printf để định dạng chuỗi./bin/bash printf không hoạt động với LANG khác hơn C

Kịch bản của tôi trông như thế này

rt=$(printf "%.3f" 13.234324245) 

với sự khác biệt, mà tôi tính toán số 13,23 ... trên. Khi tôi sử dụng/usr/bin/zsh hoạt động tốt! Ngay cả/bin/sh có thể làm điều đó (nhưng nó không thể làm nếu công cụ ...) Vấn đề lớn nhất mà/bin/bash dường như không hiểu printf hoặc không có cách thức khác khi tôi không sử dụng LANG=C.

My LANG Variable được thiết lập để de_AT.UTF-8 và sau đó tôi nhận được lỗi này:

/path/to/script: Zeile 12: printf: 13.234324245: Ungültige Zahl. 

Vì vậy, nó chỉ đơn giản nói rằng số tôi đã cung cấp printf là không hợp lệ ...

Do i cần phải chạy printf theo một cách khác?

chỉnh sửa: Vấn đề có vẻ là trên việc tính toán số:

rt=$(printf "%.3f" $(echo "$res2 - $res1"|bc)) 

làm thế nào tôi có thể nói bc sử dụng một , thay vì .?

Trả lời

4

vấn đề của bạn bắt nguồn cho các thiết lập LC_NUMERIC, mà bash sau argumen khi phân tích cú pháp ts đến printf.

Tôi thấy hành vi này không rõ ràng. Ksh93 cũng phân tích các số theo LC_NUMERIC trong khi pdksh và dấu gạch ngang muốn một dấu chấm làm dấu phân tách trong đối số và zsh chấp nhận dấu chấm hoặc định dạng cục bộ. POSIX không nói, vì định dạng điểm nổi được chỉ định là tùy chọn trong printf (LC_NUMERIC phải được tôn trọng khi in số mặc dù).

Là người dùng tôi khuyên bạn không bao giờ đặt LC_NUMERICLC_COLLATE ngoại trừ trong trường hợp rất cụ thể nơi bạn chắc chắn muốn hành vi của họ. Điều này có nghĩa là không sử dụng LANG và đặt danh mục cụ thể thay thế; hầu hết mọi người chỉ cần LC_CTYPE (mã hóa ký tự), LC_MESSAGES (ngôn ngữ của tin nhắn) và LC_TIME (định dạng ngày và giờ). Trong tập lệnh, bạn có thể ghi đè tất cả các danh mục bằng cách đặt LC_ALL hoặc danh mục cụ thể bằng cách đặt danh mục đó (đặt LANG chỉ ghi đè $LANG và không phải là người dùng đặt $LC_NUMERIC).

#!/bin/sh 
LC_NUMERIC=C LC_COLLATE=C 
printf "%.3f" 13.234324245 
2

Đây có thể là sự cố ngôn ngữ - Tôi nghĩ rằng trong dấu phân tách thập phân của Đức là dấu phẩy , thay vì khoảng thời gian .. Hãy thử sử dụng 13,234324245 làm giá trị của bạn.

+0

Điều thú vị là –

+0

nhưng sau đó, làm cách nào để làm điều đó khi phao ra khỏi bc? sed nó? D: – reox

+0

Có lẽ điều dễ nhất trong trường hợp này là sử dụng giải pháp @ J-16 và buộc LANG = C. –

2

Chỉ cần làm một $(LANG=C printf "%.3f" 13.234324245), chỉ cần đặt LANG về lệnh này

+2

Tôi khuyên bạn nên đặt 'LC_NUMERIC' thay vì' LANG', cũng để ghi đè một tập hợp 'LC_NUMERIC' do người dùng đặt. Hoặc thậm chí là 'LC_ALL'. – Gilles

1

Bạn có thể sử dụng printf hiện thực khác: với những người không được xây dựng trong/usr/bin/printf:

% # LANG is ru_RU.UTF8, decimal separator is comma 
% /usr/bin/printf %.3f 3.14 
3,140 
% /usr/bin/printf %.3f 3,14 
/usr/bin/printf: 3,14: значение преобразовано не полностью 
3,000 
% LANG=C /usr/bin/printf %.3f 3,14 
printf: 3,14: value not completely converted 
3.00 

Với zsh BUILTIN printf thực hiện:

% printf %.3f 3.14 
3,140 
% printf %.3f 3,14 
3,140