Vòng lặp While để kiểm tra xem tệp có tồn tại trong bash hay không


94

Tôi đang làm việc trên một tập lệnh shell thực hiện các thay đổi nhất định trên tệp txt chỉ khi nó tồn tại, tuy nhiên, vòng lặp kiểm tra này không hoạt động, tôi tự hỏi tại sao? Cảm ơn bạn!

while [ ! -f /tmp/list.txt ] ;
do
      sleep 2
done

3
Tôi không thể nói rằng tôi ngạc nhiên; vòng lặp đó không cố gắng thay đổi bất cứ điều gì.
Ignacio Vazquez-Abrams

Dấu chấm phẩy thừa. Theo cách nào thì vòng lặp kiểm tra đó không hoạt động? Nó sẽ ngủ lặp đi lặp lại trong 2 giây cho đến khi tệp /tmp/list.txt tồn tại.
Jonathan Leffler

5
Hoạt động đối với tôi - vòng lặp kết thúc khi tệp được tạo bên ngoài tập lệnh.

1
trên thực tế, vòng lặp này chỉ phục vụ bữa đợi cho đến khi các tập tin là có, phần còn lại của kịch bản kia cũng làm thay đổi ...: p
Zenet

1
Sau đó, vòng lặp while hoạt động, chỉ là tôi ... xin lỗi.
Zenet

Câu trả lời:


145

Khi bạn nói "không hoạt động", làm thế nào bạn biết nó không hoạt động?

Bạn có thể cố gắng tìm hiểu xem tệp có thực sự tồn tại hay không bằng cách thêm:

while [ ! -f /tmp/list.txt ]
do
  sleep 2 # or less like 0.2
done
ls -l /tmp/list.txt

Bạn cũng có thể đảm bảo rằng bạn đang sử dụng trình bao Bash (hoặc có liên quan) bằng cách nhập 'echo $ SHELL'. Tôi nghĩ rằng CSH và TCSH sử dụng một ngữ nghĩa hơi khác nhau cho vòng lặp này.


Tại sao bạn sử dụng kiểm tra tệp đảo ngược? Không nên sử dụng while [-f /tmp/list.txt] thay thế?
valentt

2
@valentt Không lặp hew nói theo nghĩa đen "trong khi không tập tin tồn tại làm giấc ngủ" .. nếu bạn muốn loại bỏ các 'KHÔNG' vòng lặp sẽ phá vỡ ngay lập tức
Kenyakorn Ketsombut

2
trong 1 dòng:while [ ! -f /tmp/list.txt ]; do sleep 2; done; ls -l /tmp/list.txt
DrumM

55

Nếu bạn đang sử dụng linux và đã cài đặt inotify-tools, bạn có thể thực hiện việc này:

file=/tmp/list.txt
while [ ! -f "$file" ]
do
    inotifywait -qqt 2 -e create -e moved_to "$(dirname $file)"
done

Điều này làm giảm độ trễ do ngủ trong khi vẫn thăm dò mỗi giây "x". Bạn có thể thêm nhiều sự kiện hơn nếu bạn dự đoán rằng chúng là cần thiết.


4
+1 cho hiệu quả. Ngủ chung với giấc ngủ là xấu. Đối với những người không biết inotifywait - nó có trong gói công cụ inotify.
Michał Šrajer

7
Đó là một công cụ cực kỳ tiện dụng. Đối với bất kỳ ai thắc mắc tại sao vòng lặp, đó là để đối phó với các điều kiện chạy đua có thể xảy ra giữa việc tạo và chờ đợi và vì inotifywait --excludephải lọc ra các tên tệp, nhưng không --includethể bỏ qua mọi thứ ngoại trừ tên tệp. Lệnh trên nên sử dụng -qqđối số thay vì >&/dev/nullmặc dù.
Craig Ringer

t có --timeoutphải là tần suất kiểm tra không? Điểm của inotifywait là không có cuộc bỏ phiếu
Alex Dean

1
@AlexDean Thời gian chờ là để ngăn chặn tình trạng cuộc đua. Bỏ phiếu với chế độ ngủ chậm vì vòng lặp sẽ không thoát ra trong chế độ ngủ, nhưng inotifywait sẽ thoát trước thời gian chờ nếu nó thấy một sự kiện.
yingted

1
@AlexDean Có, nhưng cần thiết để ngăn điều kiện đua TOCTTOU. Nếu không, inotifywaitcó thể bị treo vô thời hạn nếu một tệp được tạo ngay trước khi nó bắt đầu lắng nghe các sự kiện.
yingted

4

Tôi đã có cùng một vấn đề, đặt! ngoài dấu ngoặc;

while ! [ -f /tmp/list.txt ];
do
    echo "#"
    sleep 1
done

Ngoài ra, nếu bạn thêm tiếng vọng vào bên trong vòng lặp, nó sẽ cho bạn biết liệu bạn có đang vào vòng lặp hay không.


2

Tôi đã gặp phải một vấn đề tương tự và nó dẫn tôi đến đây vì vậy tôi chỉ muốn để lại giải pháp của mình cho bất kỳ ai có cùng kinh nghiệm.

Tôi nhận thấy rằng nếu tôi chạy cat /tmp/list.txttệp sẽ trống, mặc dù tôi chắc chắn rằng có nội dung được đặt ngay trong tệp. Hóa ra nếu tôi đặt sleep 1;ngay trước khi cat /tmp/list.txtnó hoạt động như mong đợi. Chắc hẳn đã có một khoảng thời gian trễ giữa thời gian tệp được tạo và thời gian nó được viết, hoặc một cái gì đó dọc theo những dòng đó.

Mã cuối cùng của tôi:

while [ ! -f /tmp/list.txt ];
do
    sleep 1;
done;
sleep 1;
cat /tmp/list.txt;

Hy vọng điều này sẽ giúp tiết kiệm cho ai đó nửa giờ bực bội!


1

Giống như @ zane-hooper, tôi đã gặp sự cố tương tự trên NFS. Trên hệ thống tệp song song / phân tán, độ trễ giữa bạn tạo tệp trên máy này và máy khác "nhìn thấy" tệp đó có thể rất lớn, vì vậy tôi có thể đợi tối đa một phút sau khi tạo tệp trước khi vòng lặp while thoát ra (và cũng có một hậu quả của việc nó "nhìn thấy" một tệp đã bị xóa).

Điều này tạo ra ảo tưởng rằng script "không hoạt động" , trong khi thực tế nó là hệ thống tập tin đang thả bóng.

Điều này khiến tôi mất một lúc để tìm ra, hy vọng nó sẽ tiết kiệm cho ai đó một chút thời gian.

PS Điều này cũng gây ra một số lỗi "Trình xử lý tệp cũ" khó chịu.


0

hoạt động với cả bash và sh:

touch /tmp/testfile
sleep 10 && rm /tmp/testfile &
until ! [ -f /tmp/testfile ]
do
   echo "testfile still exist..."
   sleep 1
done
echo "now testfile is deleted.."

0

Đây là phiên bản có thời gian chờ để sau một khoảng thời gian, vòng lặp kết thúc với lỗi:

# After 60 seconds the loop will exit
timeout=60

while [ ! -f /tmp/list.txt ];
do
  # When the timeout is equal to zero, show an error and leave the loop.
  if [ "$timeout" == 0 ]; then
    echo "ERROR: Timeout while waiting for the file /tmp/list.txt."
    exit 1
  fi

  sleep 1

  # Decrease the timeout of one
  ((timeout--))
done

-3

làm nó như thế này

while true
do
  [ -f /tmp/list.txt ] && break
  sleep 2
done
ls -l /tmp/list.txt
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.