Đặt đầu ra của lệnh nếu thành công


14
INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml | head -1 | xargs basename`

Tôi muốn thực hiện lệnh thứ hai ( head -1) chỉ khi lệnh đầu tiên thành công. Làm thế nào để tôi cải thiện lệnh này?


Bạn có ý nghĩa gì khi thành công? lssẽ không thất bại.
Matteo

2
Nhưng toàn cầu có thể thất bại nếu không có tệp phù hợp.
tripleee

Câu trả lời:


8

Thử đi:

INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml | head -1 | xargs -r basename`

Đi qua xargsnhững -rlá cờ sẽ gây ra nó để chỉ chạy basenamenếu đọc ít nhất một mục từ đầu vào chuẩn ( head -1).

head -1 sẽ chạy nhưng bạn sẽ không thấy hoặc nắm bắt bất kỳ đầu ra nào từ nó.

Ngoài ra, nếu bạn không muốn người dùng thấy bất kỳ đầu ra lỗi nào ls, bạn có thể chuyển hướng lsluồng stderr của mình sang /dev/null.

INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename`

Cũng lưu ý rằng tôi đã thêm dấu ngoặc kép xung quanh $MY_DIR. Bằng cách đó, lệnh sẽ không thất bại nếu $MY_DIRchứa khoảng trắng.

Nếu bạn đang sử dụng trình bao hiện đại như bash, bạn nên sử dụng trình $( )bao chụp thay vì backticks. Bạn cũng nên xem xét việc thay đổi phong cách của các biến của bạn. Nói chung, bạn nên tránh sử dụng tên biến toàn chữ hoa trong tập lệnh. Phong cách đó thường được dành riêng cho các biến môi trường và dành riêng.

input_file=$(ls -rt "$my_dir"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename)

Không b0rk này nếu không có tập tin?
Mel Boyce

Trên thực tế: ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basenamecông trình.
Mel Boyce

@MelBoyce: Tôi đã thêm nó vào câu trả lời của mình. Cảm ơn.

ls là một công cụ để tương tác xem thông tin tập tin. Đầu ra của nó được định dạng cho con người và sẽ gây ra lỗi trong các tập lệnh. Sử dụng quả cầu hoặc tìm thay thế. Hiểu tại sao: mywiki.wooledge.org/ParsingLs
Cinelli

@cinelli: Đó là sự thật. Tôi chỉ trả lời câu hỏi.

9

Trong một đường ống, tất cả các lệnh được bắt đầu và chạy đồng thời, không phải lần lượt từng lệnh. Vì vậy, bạn cần lưu trữ đầu ra ở đâu đó.

if ls_output=$(ls -rtd -- "$MY_DIR"/FILE.*.xml); then
  first_file=$(printf '%s\n' "$ls_output" | head -n 1)
  first_file_name=$(basename -- "$first_file")
fi

Lưu ý rằng nó giả sử tên tệp không chứa ký tự dòng mới. Sử dụng xargscũng có nghĩa là các vấn đề với các ký tự trống, dấu ngoặc đơn và dấu ngoặc kép và dấu gạch chéo ngược. Để các biến không được trích dẫn có nghĩa là các vấn đề với không gian, tab và ký tự đại diện. Quên --có nghĩa là vấn đề với tên tệp bắt đầu bằng -.

Để có được tên cơ sở của tệp cũ nhất zshmà không có bất kỳ hạn chế nào đối với các ký tự (cũng tránh vấn đề về kích thước giới hạn của các đối số đối với một lệnh):

 first_file_name=($MY_DIR/FILE.*.xml(Om[1]:t))

Nếu không có kết quả khớp, lệnh đó sẽ thất bại và hủy bỏ tập lệnh. Bạn cũng có thể làm:

 first_file_name=($MY_DIR/FILE.*.xml(NOm[1]:t))

Trong trường hợp đó, first_file_namemảng sẽ chứa 1 phần tử nếu có khớp hoặc 0 nếu không. Sau đó bạn có thể làm:

 if (($#first_file_name)); then
    printf 'Match: %s\n' $first_file_name
 else
    echo >&2 No match
 fi

4

Tìm tập tin sửa đổi mới nhất trong một thư mục:

latest() {
  local file path=${1:-.} ext=${2-} latest
  for file in "${path%/}"/*"$ext"; do 
    [[ $file -nt $latest ]] && latest=$file
  done
  [[ $latest ]] && printf '%s\n' "$latest"
}

Sử dụng: latest [directory/path/ [.extension]]

Thay vì gọi ra basename, sử dụng mở rộng tham số.

in_file=$(latest in/my/dir .xml)
base_fn=${in_file##*/} base_fn=${base_fn%.*}

Trong một thư mục có các nội dung này:

foo.xml bar.xml baz.xml newest.xml

Nội dung của biến base_fn sẽ là: newest

Để sử dụng đúng cách để phục vụ mục đích yêu cầu của bạn:

check_dir=/path/to/check
check_ext=.xml
if in_file=$(latest "$check_dir" "$check_ext"); then
  base_fn=${in_file##*/} base_fn=${base_fn%.*}
else
  printf '%s\n' "No file found in $check_dir" >&2
fi

EDIT: khi xem xét câu hỏi, tôi đã nhận ra rằng lslệnh trong câu hỏi đang tìm kiếm tệp cũ nhất trong một thư mục. chức năng tương tự này có thể được đổi tên thành oldest[[ $file -ot $oldest ]] && oldest=$filethay vào đó để đạt được hiệu quả tương tự. xin lỗi vì sự nhầm lẫn

điều quan trọng cần lưu ý là bạn tuyệt đối, trong mọi trường hợp không bao giờ có trong nhân loại, không nên phân tích đầu ra của ls. không bao giờ.


Lưu ý rằng trái với các lsphương pháp dựa trên cơ sở, nếu có liên kết tượng trưng, ​​thời gian sửa đổi mục tiêu của các liên kết tượng trưng sẽ được xem xét (thêm -Ltùy chọn lsđể có hành vi tương tự ở đó).
Stéphane Chazelas

0

Tôi nghĩ rằng lựa chọn tốt nhất ở đây là:

ls -rf $MY_DIR/FILE.*.xml
if [ $? -eq 0 ]; then
      INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml|head -1|xargs basename `
else
      echo "Error!"
fi

nếu không có tệp thì mã trả về của ls là 2 nhưng nếu tìm thấy một số tệp sẽ là 0.


2
Thay vì so sánh $?với 0, bạn có thể làm điều này : if ls -rf $MY_DIR/FILE.*.xml ; then.

Ngoài ra, bạn có thể chuyển hướng đầu ra của lần đầu tiên đến /dev/null. ls -rf $MY_DIR/FILE.*.xml &> /dev/null. Bằng cách đó, người dùng sẽ không thấy đầu ra thêm.
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.