2011-05-04 20 views
75

Trong Bash, tôi muốn tạo hàm trả về tên tệp của tệp mới nhất khớp với mẫu nhất định. Ví dụ: tôi có một thư mục chứa các tệp như:Hàm Bash để tìm mẫu phù hợp với tệp mới nhất

Directory/ 
    a1.1_5_1 
    a1.2_1_4 
    b2.1_0 
    b2.2_3_4 
    b2.3_2_0 

Tôi muốn tệp mới nhất bắt đầu bằng 'b2'. Làm thế nào để làm điều này trong bash? Tôi cần có điều này trong tập lệnh ~/.bash_profile của mình.

+1

xem http://superuser.com/questions/294161/unix-linux-find-and-sort-by-date-modified để có thêm gợi ý câu trả lời. Việc phân loại là bước quan trọng để lấy tập tin mới nhất của bạn –

Trả lời

139

Lệnh ls có thông số -t để sắp xếp theo thời gian. Sau đó bạn có thể lấy đầu tiên (mới nhất) với head -1.

ls -t b2* | head -1 

Nhưng hãy cẩn thận: Why you shouldn't parse the output of ls

ý kiến ​​cá nhân của tôi: phân tích ls chỉ nguy hiểm khi tên tập tin có thể chứa các ký tự buồn cười như không gian hoặc dòng mới. Nếu bạn có thể đảm bảo rằng tên tệp sẽ không chứa các ký tự vui thì phân tích cú pháp ls là khá an toàn.

Nếu bạn đang phát triển tập lệnh được nhiều người trên nhiều hệ thống trong nhiều tình huống khác nhau chạy thì tôi khuyên bạn không nên phân tích cú pháp ls.

Sau đây là cách để làm điều đó "đúng":. How can I find the latest (newest, earliest, oldest) file in a directory?

unset -v latest 
for file in "$dir"/*; do 
    [[ $file -nt $latest ]] && latest=$file 
done 
+5

Lưu ý cho người khác: nếu bạn đang làm điều này cho một thư mục, bạn sẽ thêm tùy chọn -d vào ls, như thế này 'ls -td | đầu -1 ' –

+4

Liên kết [phân tích cú pháp LS] (http://mywiki.wooledge.org/ParsingLs) nói không làm điều này và đề xuất các phương pháp trong [BashFAQ 99] (http://mywiki.wooledge.org/BashFAQ/099). Tôi đang tìm kiếm một lớp lót hơn là một cái gì đó chống đạn để bao gồm trong một kịch bản, vì vậy tôi sẽ tiếp tục phân tích ls unsafely như @lesmana. – Eponymous

+0

@Eponymous: Nếu bạn đang tìm kiếm một lớp lót mà không sử dụng "ls'," printf "% s \ n" b2 * | đầu -1' sẽ làm điều đó cho bạn. –

2

tên tập tin bất thường (ví dụ như một tập tin có chứa các \n ký tự hợp lệ có thể tàn phá với loại hình phân tích Dưới đây là một cách để làm điều đó trong Perl:

perl -le '@sorted = map {$_->[0]} 
        sort {$a->[1] <=> $b->[1]} 
        map {[$_, -M $_]} 
        @ARGV; 
      print $sorted[0] 
' b2* 

đó là một Schwartzian transform sử dụng có

+0

May schwartz ở bên bạn! –

+0

câu trả lời này có thể làm việc nhưng tôi sẽ không tin tưởng nó cho các tài liệu hướng dẫn người nghèo. –

+1

tài liệu kém? nó đi kèm với một wikipage ... –

4

Đây là một thực thể của. hàm Bash bắt buộc:

# Print the newest file, if any, matching the given pattern 
# Example usage: 
# newest_matching_file 'b2*' 
# WARNING: Files whose names begin with a dot will not be checked 
function newest_matching_file 
{ 
    # Use ${1-} instead of $1 in case 'nounset' is set 
    local -r glob_pattern=${1-} 

    if (($# != 1)) ; then 
     echo 'usage: newest_matching_file GLOB_PATTERN' >&2 
     return 1 
    fi 

    # To avoid printing garbage if no files match the pattern, set 
    # 'nullglob' if necessary 
    local -i need_to_unset_nullglob=0 
    if [[ ":$BASHOPTS:" != *:nullglob:* ]] ; then 
     shopt -s nullglob 
     need_to_unset_nullglob=1 
    fi 

    newest_file= 
    for file in $glob_pattern ; do 
     [[ -z $newest_file || $file -nt $newest_file ]] \ 
      && newest_file=$file 
    done 

    # To avoid unexpected behaviour elsewhere, unset nullglob if it was 
    # set by this function 
    ((need_to_unset_nullglob)) && shopt -u nullglob 

    # Use printf instead of echo in case the file name begins with '-' 
    [[ -n $newest_file ]] && printf '%s\n' "$newest_file" 

    return 0 
} 

Chỉ sử dụng nội trang Bash và xử lý các tệp có tên chứa dòng mới hoặc các ký tự không bình thường khác.

+0

Bạn có thể sử dụng 'nullglob_shopt = $ (shopt -p nullglob)' và sau đó '$ nullglob' để đặt lại' nullglob' như thế nào trước đây. –

+0

Đề xuất của @gniourf_gniourf để sử dụng $ (shopt -p nullglob) là một gợi ý tốt. Tôi thường cố gắng tránh sử dụng lệnh thay thế ('$()' hoặc backticks) bởi vì nó là chậm, đặc biệt là dưới Cygwin, ngay cả khi lệnh chỉ sử dụng nội trang. Ngoài ra, ngữ cảnh subshell trong đó các lệnh được chạy đôi khi có thể khiến chúng hoạt động theo những cách bất ngờ. Tôi cũng cố gắng tránh lưu trữ các lệnh trong các biến (như 'nullglob_shopt') bởi vì những điều rất xấu có thể xảy ra nếu bạn nhận được giá trị của biến sai. – pjh

+0

Tôi đánh giá cao sự chú ý đến các chi tiết có thể dẫn đến thất bại tối nghĩa khi bị bỏ qua. Cảm ơn! –

2

Có một cách hiệu quả hơn để đạt được điều này. Hãy xem xét lệnh sau:

find . -cmin 1 -name "b2*" 

Lệnh này tìm tệp mới nhất được tạo bằng cách tìm kiếm ký tự đại diện trên "b2 *". Nếu bạn muốn tệp từ hai ngày qua thì bạn nên sử dụng lệnh dưới đây:

find . -mtime 2 -name "b2*" 

"." đại diện cho thư mục hiện tại. Hy vọng điều này sẽ hữu ích.

+5

Điều này không thực sự tìm thấy "mẫu phù hợp với tệp mới nhất" ... nó chỉ tìm thấy tất cả các tệp khớp với mẫu được tạo một phút trước hoặc được sửa đổi hai ngày trước. – GnP

+0

Câu trả lời này dựa trên câu hỏi đặt ra. Ngoài ra, bạn có thể tinh chỉnh lệnh để xem tệp mới nhất đã có trong một ngày trước đó. Nó phụ thuộc vào những gì bạn đang cố gắng làm. – Naufal

2

Sự kết hợp của findls hoạt động tốt cho

  • tên tập tin mà không cần newlines
  • lượng
  • không phải là rất lớn các tập tin tên tập tin
  • không phải là rất dài

Giải pháp:

find . -name "my-pattern" ... -print | 
    xargs -0 ls -1 -t | 
    head -1 

Hãy phá vỡ nó xuống:

Với find chúng ta có thể phù hợp với tất cả các file thú vị như thế này:

find . -name "my-pattern" ... 

sau đó sử dụng -print0 chúng ta có thể vượt qua tất cả tên tập tin một cách an toàn để các ls như thế này:

find . -name "my-pattern" ... -print0 | xargs -0 ls -1 -t 

ls -t sẽ sắp xếp tệp bằng cách sửa đổi thời gian (mới nhất đầu tiên) và in nó tại một dòng. Bạn có thể sử dụng -c để sắp xếp theo thời gian tạo. Lưu ý: điều này sẽ vi phạm với tên tệp có chứa dòng mới.

Cuối cùng head -1 cho chúng tôi tệp đầu tiên trong danh sách được sắp xếp.

Lưu ý:xargs sử dụng giới hạn hệ thống đối với kích thước của danh sách đối số. Nếu kích thước này vượt quá, xargs sẽ gọi ls nhiều lần. Điều này sẽ phá vỡ phân loại và có lẽ cũng là kết quả cuối cùng. Chạy

xargs --show-limits 

để kiểm tra giới hạn trên hệ thống của bạn.

Các vấn đề liên quan