Làm thế nào tôi có thể kiểm tra nếu một lệnh xuất ra một chuỗi rỗng?
ifne
cho việc này. joeyh.name/code/moreutils
Làm thế nào tôi có thể kiểm tra nếu một lệnh xuất ra một chuỗi rỗng?
ifne
cho việc này. joeyh.name/code/moreutils
Câu trả lời:
Trước đây, câu hỏi hỏi làm thế nào để kiểm tra xem có tập tin nào trong một thư mục không. Đoạn mã sau đạt được điều đó, nhưng hãy xem câu trả lời của rsp để có giải pháp tốt hơn.
Các lệnh không trả về giá trị - chúng xuất ra chúng. Bạn có thể nắm bắt đầu ra này bằng cách sử dụng thay thế lệnh ; ví dụ $(ls -A)
. Bạn có thể kiểm tra chuỗi không trống trong Bash như thế này:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
Lưu ý rằng tôi đã sử dụng -A
chứ không phải -a
vì nó bỏ qua các mục nhập thư mục hiện tại ( .
) và cha ( ..
) tượng trưng .
Lưu ý: Như đã chỉ ra trong các nhận xét, thay thế lệnh không nắm bắt được các dòng mới . Do đó, nếu các kết quả đầu ra lệnh chỉ dòng mới, sự thay thế sẽ nắm bắt được gì cả và kiểm tra sẽ trả về false. Mặc dù rất khó xảy ra, nhưng điều này là có thể trong ví dụ trên, vì một dòng mới là tên tệp hợp lệ! Thêm thông tin trong câu trả lời này .
Nếu bạn muốn kiểm tra xem lệnh đã hoàn thành thành công hay chưa, bạn có thể kiểm tra $?
, trong đó có chứa mã thoát của lệnh cuối cùng (không cho thành công, khác không cho thất bại). Ví dụ:
files=$(ls -A)
if [[ $? != 0 ]]; then
echo "Command failed."
elif [[ $files ]]; then
echo "Files found."
else
echo "No files found."
fi
Thêm thông tin ở đây .
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi
Cảm ơn netj
về một gợi ý để cải thiện bản gốc của tôi:if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi
Đây là một câu hỏi cũ nhưng tôi thấy ít nhất hai điều cần cải thiện hoặc ít nhất là làm rõ.
Vấn đề đầu tiên tôi thấy là hầu hết các ví dụ được cung cấp ở đây đơn giản là không hoạt động . Họ sử dụng các lệnh ls -al
và ls -Al
- cả hai đều xuất ra các chuỗi không trống trong các thư mục trống. Những ví dụ này luôn báo cáo rằng có các tệp ngay cả khi không có .
Vì lý do đó, bạn chỉ nên sử dụng ls -A
- Tại sao mọi người muốn sử dụng công -l
tắc có nghĩa là "sử dụng định dạng danh sách dài" khi tất cả những gì bạn muốn là kiểm tra xem có đầu ra nào hay không?
Vì vậy, hầu hết các câu trả lời ở đây chỉ đơn giản là không chính xác.
Vấn đề thứ hai là trong khi một số câu trả lời làm việc tốt (những người không sử dụng ls -al
hoặc ls -Al
nhưng ls -A
thay vào đó) tất cả họ đều làm một cái gì đó như thế này:
Những gì tôi sẽ đề nghị làm thay vào đó sẽ là:
using head -c1
Vì vậy, ví dụ, thay vì:
if [[ $(ls -A) ]]
Tôi sẽ dùng:
if [[ $(ls -A | wc -c) -ne 0 ]]
# or:
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]
Thay vì:
if [ -z "$(ls -lA)" ]
Tôi sẽ dùng:
if [ $(ls -lA | wc -c) -eq 0 ]
# or:
if [ $(ls -lA | head -c1 | wc -c) -eq 0 ]
và như thế.
Đối với đầu ra nhỏ, nó có thể không phải là vấn đề nhưng đối với đầu ra lớn hơn, sự khác biệt có thể là đáng kể:
$ time [ -z "$(seq 1 10000000)" ]
real 0m2.703s
user 0m2.485s
sys 0m0.347s
So sánh nó với:
$ time [ $(seq 1 10000000 | wc -c) -eq 0 ]
real 0m0.128s
user 0m0.081s
sys 0m0.105s
Và thậm chí tốt hơn:
$ time [ $(seq 1 10000000 | head -c1 | wc -c) -eq 0 ]
real 0m0.004s
user 0m0.000s
sys 0m0.007s
Ví dụ cập nhật từ câu trả lời của Will Vousden:
if [[ $(ls -A | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
Cập nhật lại sau khi đề xuất bởi netj :
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
Cập nhật bổ sung bởi jakeonfire :
grep
sẽ thoát với một thất bại nếu không có trận đấu. Chúng ta có thể tận dụng điều này để đơn giản hóa cú pháp một chút:
if ls -A | head -c1 | grep -E '.'; then
echo "there are files"
fi
if ! ls -A | head -c1 | grep -E '.'; then
echo "no files found"
fi
Nếu lệnh mà bạn đang kiểm tra có thể xuất ra một số khoảng trắng mà bạn muốn coi là một chuỗi rỗng, thì thay vì:
| wc -c
bạn đã có thể sử dụng:
| tr -d ' \n\r\t ' | wc -c
hoặc với head -c1
:
| tr -d ' \n\r\t ' | head -c1 | wc -c
hoặc điều tương tự.
Đầu tiên, sử dụng một lệnh hoạt động .
Thứ hai, tránh lưu trữ không cần thiết trong RAM và xử lý dữ liệu có khả năng rất lớn.
Câu trả lời không xác định rằng đầu ra luôn nhỏ, do đó, khả năng đầu ra lớn cũng cần được xem xét.
[[ $(... | head -c | wc -c) -gt 0 ]]
hoặc [[ -n $(... | head -c1) ]]
là tốt hơn bởi vì wc -c
sẽ phải tiêu thụ toàn bộ đầu ra của lệnh.
if [ -z "$(ls -lA)" ]; then
echo "no files found"
else
echo "There are files"
fi
Điều này sẽ chạy lệnh và kiểm tra xem đầu ra được trả về (chuỗi) có độ dài bằng không. Bạn có thể muốn kiểm tra các trang hướng dẫn 'kiểm tra' để tìm các cờ khác.
Sử dụng "" xung quanh đối số đang được kiểm tra, nếu không, kết quả trống sẽ dẫn đến lỗi cú pháp vì không có đối số thứ hai (để kiểm tra) được đưa ra!
Lưu ý: ls -la
luôn luôn trả về .
và ..
do đó sử dụng sẽ không hoạt động, xem các trang hướng dẫn ls . Hơn nữa, trong khi điều này có vẻ thuận tiện và dễ dàng, tôi cho rằng nó sẽ dễ dàng bị phá vỡ. Viết một tập lệnh / ứng dụng nhỏ trả về 0 hoặc 1 tùy theo kết quả sẽ đáng tin cậy hơn nhiều!
$(
thay vì backquote, vì $(
làm tổ tốt hơn
Đối với những người muốn một giải pháp độc lập, bash phiên bản độc lập (trên thực tế nên hoạt động trong các trình bao hiện đại khác) và những người thích sử dụng một lớp lót cho các nhiệm vụ nhanh chóng. Chúng ta đi đây!
ls | grep . && echo 'files found' || echo 'files not found'
(lưu ý là một trong những ý kiến được đề cập, ls -al
và trên thực tế, tất cả -l
và -a
sẽ trả lại một cái gì đó, vì vậy trong câu trả lời của tôi, tôi sử dụng đơn giảnls
grep -q ^
thay thế, các ký tự dòng mới cũng sẽ được khớp và grep sẽ không in bất cứ thứ gì ra đầu ra tiêu chuẩn. Hơn nữa, nó sẽ thoát ngay khi nhận được bất kỳ đầu vào nào, thay vì chờ luồng đầu vào kết thúc.
ls -A
nếu bạn muốn bao gồm các tệp dấu chấm (hoặc thư mục)
-z string
True if the length of string is zero.
-n string
string
True if the length of string is non-zero.
Bạn có thể sử dụng phiên bản tốc ký:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
string
là một từ đồng nghĩa với -n string
.
Như Jon Lin đã nhận xét, ls -al
sẽ luôn xuất ra (cho .
và ..
). Bạn muốn ls -Al
tránh hai thư mục này.
Ví dụ, bạn có thể đặt đầu ra của lệnh vào một biến shell:
v=$(ls -Al)
Một ký hiệu cũ hơn, không thể lồng được là
v=`ls -Al`
nhưng tôi thích ký hiệu lồng nhau $(
...)
Các bạn có thể kiểm tra nếu biến đó không trống
if [ -n "$v" ]; then
echo there are files
else
echo no files
fi
Và bạn có thể kết hợp cả hai như if [ -n "$(ls -Al)" ]; then
Tôi đoán bạn muốn đầu ra của ls -al
lệnh, vì vậy trong bash, bạn sẽ có một cái gì đó như:
LS=`ls -la`
if [ -n "$LS" ]; then
echo "there are files"
else
echo "no files found"
fi
ls
không bao giờ được thực thi. Bạn chỉ kiểm tra xem việc mở rộng biến LS
có trống không.
-a
tắc sẽ không bao giờ trả lại nội dung (nghĩa là nó sẽ trả về nội dung cho dù có tệp hay không) vì luôn có các thư mục ẩn .
và ..
thư mục hiện diện.
Đây là một giải pháp cho các trường hợp cực đoan hơn:
if [ `command | head -c1 | wc -c` -gt 0 ]; then ...; fi
Điều này sẽ làm việc
Tuy nhiên,
Tất cả các câu trả lời cho đến nay đều xử lý các lệnh kết thúc và xuất ra một chuỗi không trống.
Hầu hết bị phá vỡ trong các giác quan sau:
yes
).Vì vậy, để khắc phục tất cả các vấn đề này và để trả lời câu hỏi sau một cách hiệu quả,
Làm thế nào tôi có thể kiểm tra nếu một lệnh xuất ra một chuỗi rỗng?
bạn có thể dùng:
if read -n1 -d '' < <(command_here); then
echo "Command outputs something"
else
echo "Command doesn't output anything"
fi
Bạn cũng có thể thêm một số thời gian chờ để kiểm tra xem một lệnh kết quả đầu ra một chuỗi không có sản phẩm nào trong một thời gian nhất định, sử dụng read
's -t
lựa chọn. Ví dụ: trong khoảng thời gian chờ 2,5 giây:
if read -t2.5 -n1 -d '' < <(command_here); then
echo "Command outputs something"
else
echo "Command doesn't output anything"
fi
Ghi chú. Nếu bạn nghĩ rằng bạn cần xác định xem một lệnh có tạo ra một chuỗi không trống hay không, rất có thể bạn có vấn đề XY.
seq 1 10000000
, seq 1 20
và printf""
). Cách tiếp cận duy nhất mà phương pháp đọc này không thắng là với -z "$(command)"
cách tiếp cận cho đầu vào trống. Thậm chí sau đó, nó chỉ thua khoảng 10-15%. Họ dường như phá vỡ thậm chí xung quanh seq 1 10
. Bất kể, -z "$(command)"
cách tiếp cận trở nên quá chậm khi kích thước đầu vào tăng lên mà tôi tránh sử dụng nó cho bất kỳ đầu vào có kích thước thay đổi nào.
Đây là một cách tiếp cận khác để ghi std-out và std-err của một số lệnh một tệp tạm thời, sau đó kiểm tra xem tệp đó có trống không. Một lợi ích của phương pháp này là nó thu được cả hai đầu ra và không sử dụng vỏ phụ hoặc ống dẫn. Những khía cạnh sau này rất quan trọng vì chúng có thể can thiệp vào việc xử lý thoát bẫy bash (ví dụ ở đây )
tmpfile=$(mktemp)
some-command &> "$tmpfile"
if [[ $? != 0 ]]; then
echo "Command failed"
elif [[ -s "$tmpfile" ]]; then
echo "Command generated output"
else
echo "Command has no output"
fi
rm -f "$tmpfile"
Đôi khi bạn muốn lưu kết quả đầu ra, nếu nó không trống, để chuyển nó sang một lệnh khác. Nếu vậy, bạn có thể sử dụng một cái gì đó như
list=`grep -l "MY_DESIRED_STRING" *.log `
if [ $? -eq 0 ]
then
/bin/rm $list
fi
Bằng cách này, rm
lệnh sẽ không bị treo nếu danh sách trống.