Làm cách nào để kiểm tra xem tập tin có tồn tại trong tập lệnh shell hay không


175

Tôi muốn viết một tập lệnh shell để kiểm tra nếu một tập tin nhất định archived_sensor_data.json, tồn tại và nếu có, sẽ xóa nó. Theo dõi http://www.cyberciti.biz/tips/find-out-if-file-exists-with-conditable-expressions.html , tôi đã thử như sau:

[-e archived_sensor_data.json] && rm archived_sensor_data.json

Tuy nhiên, điều này ném một lỗi

[-e: command not found

khi tôi cố chạy test_controllertập lệnh kết quả bằng ./test_controllerlệnh. Có gì sai với mã?



2
Bạn phải đặt một hoặc nhiều khoảng trắng giữa mở dấu ngoặc vuông "[" và tùy chọn "-e" giống như giữa tên tệp và đóng dấu ngoặc vuông "]"
Konstantin Yaniv

Câu trả lời:


349

Bạn đang thiếu một không gian cần thiết giữa khung và -e:

#!/bin/bash
if [ -e x.txt ]
then
    echo "ok"
else
    echo "nok"
fi

12
Cuối cùng tôi đã thêm hai khoảng trắng, một sau dấu ngoặc vuông mở và một trước dấu đóng : [ -e archived_sensor_data.json ] && rm archived_sensor_data.json. Kịch bản dường như hoạt động ngay bây giờ.
Kurt Peek

3
Điều này cũng hoạt động bằng cách sử dụng if [ -e "$1" ](đối số đầu vào tên tệp).
Edward

2
Sự khác biệt chính ở đây là thực tế là bạn đang sử dụng tập lệnh "bash" thay vì tập lệnh "shell". Lưu ý rằng dòng đầu tiên bạn đã thêm là #! / Bin / bash, vì vậy bạn đang bảo máy sử dụng "bash" thay vì sh. Bởi vì sh không nhận ra lập luận đó "-e"
Nick Cuevas

29

Đây là một phương pháp thay thế bằng cách sử dụng ls:

(ls x.txt && echo yes) || echo no

Nếu bạn muốn ẩn bất kỳ đầu ra nào lsđể bạn chỉ thấy có hoặc không, hãy chuyển hướng stdoutstderrđến/dev/null :

(ls x.txt >> /dev/null 2>&1 && echo yes) || echo no

1
Mã này có nghĩa là: "nếu lsthành công, có tệp như vậy, nếu không, không có". Nếu lsthất bại, điều đó không có nghĩa là tập tin bị thiếu. Nó có thể là một số lỗi khác. Ví dụ: tạo tệp trong thư mục thuộc sở hữu của root và cố gắng thực hiện lstheo người dùng thông thường. Nó sẽ thất bại với Permission denied, không tương đương với tập tin không tồn tại.
Tigran

9

Bối cảnh cho đề xuất giải pháp của tôi là câu chuyện về một người bạn, vào tuần thứ hai của công việc đầu tiên, đã xóa sạch một nửa máy chủ xây dựng. Vì vậy, nhiệm vụ cơ bản là tìm ra nếu một tập tin tồn tại, và nếu vậy, hãy xóa nó. Nhưng có một vài thác ghềnh trên sông này:

  • Tất cả mọi thứ là một tập tin.

  • Các kịch bản chỉ có sức mạnh thực sự nếu chúng giải quyết các nhiệm vụ chung

  • Để nói chung, chúng tôi sử dụng các biến

  • Chúng tôi thường sử dụng lực -f trong các tập lệnh để tránh can thiệp thủ công

  • Và cũng yêu -r đệ quy để đảm bảo chúng tôi tạo, sao chép và phá hủy một cách kịp thời.

Hãy xem xét kịch bản sau đây:

Chúng tôi có tệp chúng tôi muốn xóa: filesexists.json

Tên tệp này được lưu trữ trong một biến

<host>:~/Documents/thisfolderexists filevariable="filesexists.json"

Chúng tôi cũng có một biến số đường dẫn để làm cho mọi thứ thực sự linh hoạt

<host>:~/Documents/thisfolderexists pathtofile=".."

<host>:~/Documents/thisfolderexists ls $pathtofile

filesexists.json  history20170728  SE-Data-API.pem  thisfolderexists

Vì vậy, hãy xem nếu -enó làm những gì nó được cho là. Liệu các tập tin tồn tại?

<host>:~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $?

0

Nó làm. Ma thuật.

Tuy nhiên, điều gì sẽ xảy ra, nếu biến tệp bị vô tình được đánh giá là nuffin '

<host>:~/Documents/thisfolderexists filevariable=""

<host>:~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $?

0

Gì? Nó được cho là quay trở lại với một lỗi ... Và đây là khởi đầu của câu chuyện làm thế nào toàn bộ thư mục bị xóa do tai nạn

Một cách khác có thể là kiểm tra cụ thể những gì chúng tôi hiểu là 'tệp'

<host>:~/Documents/thisfolderexists filevariable="filesexists.json"

<host>:~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $?

0

Vì vậy, tập tin tồn tại ...

<host>:~/Documents/thisfolderexists filevariable=""

<host>:~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $?

1

Vì vậy, đây không phải là một tập tin và có lẽ, chúng tôi không muốn xóa toàn bộ thư mục đó

man test có những điều sau đây để nói:

-b FILE

       FILE exists and is block special

-c FILE

       FILE exists and is character special

-d FILE

       FILE exists and is a directory

-e FILE

       FILE exists

-f FILE

       FILE exists and is a regular file

...

-h FILE

       FILE exists and is a symbolic link (same as -L)

4

Trong nội bộ, lệnh rm phải kiểm tra sự tồn tại của tập tin nào,
vậy tại sao lại thêm một thử nghiệm khác? Chỉ cần vấn đề

rm filename

và nó sẽ biến mất sau đó, dù nó có ở đó hay không.
Sử dụng rm -f là bạn không muốn có bất kỳ tin nhắn nào về các tệp không tồn tại.

Nếu bạn cần thực hiện một số hành động nếu tệp KHÔNG tồn tại, thì bạn phải tự kiểm tra. Dựa trên mã ví dụ của bạn, đây không phải là trường hợp trong trường hợp này.


1
Đây thực sự là một câu trả lời hợp lệ cho lệnh rm. Đối với các lệnh khác, tôi đề nghị thay vì thử nghiệm với -e.
warhansen

Ngoại trừ đó không phải là những gì câu hỏi yêu cầu.
Crayons

1
Đó là rất nhiều những gì câu hỏi yêu cầu, nếu bạn đọc toàn bộ câu hỏi bao gồm cả phần "... và (nếu vậy) ... xóa nó".
TG

1

Nếu bạn đang sử dụng NFS, "test" là một giải pháp tốt hơn, bởi vì bạn có thể thêm thời gian chờ vào nó, trong trường hợp NFS của bạn bị hỏng:

time timeout 3 test -f 
/nfs/my_nfs_is_currently_down
real    0m3.004s <<== timeout is taken into account
user    0m0.001s
sys     0m0.004s
echo $?
124   <= 124 means the timeout has been reached

Cấu trúc "[-e my_file]" sẽ đóng băng cho đến khi NFS hoạt động trở lại:

if [ -e /nfs/my_nfs_is_currently_down ]; then echo "ok" else echo "ko" ; fi

<no answer from the system, my session is "frozen">

test[đồng nghĩa. Bạn có thể sử dụng timeoutvới [là tốt, và testcũng bị đóng băng nếu NFS bị treo.
anh chàng kia
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.