ไพพ์เอาต์พุตของคำสั่งหากสำเร็จ


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

ฉันต้องการรันคำสั่งที่สอง ( head -1) เฉพาะเมื่อคำสั่งแรกสำเร็จ ฉันจะปรับปรุงคำสั่งนี้ได้อย่างไร


คุณหมายถึงอะไรที่ประสบความสำเร็จ? lsจะไม่ล้มเหลว
Matteo

2
แต่ glob อาจล้มเหลวได้หากไม่มีไฟล์ที่ตรงกัน
tripleee

คำตอบ:


8

ลองสิ่งนี้:

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

การผ่านxargsการ-rตั้งค่าสถานะจะทำให้การทำงานนั้นต่อbasenameเมื่ออ่านอย่างน้อยหนึ่งรายการจากอินพุตมาตรฐาน ( head -1)

head -1 จะทำงาน แต่คุณจะไม่เห็นหรือบันทึกผลลัพธ์ใด ๆ จากมัน

นอกจากนี้ถ้าคุณไม่ต้องการให้ผู้ใช้เพื่อดูออกข้อผิดพลาดใด ๆ จากlsคุณสามารถเปลี่ยนเส้นทางlsของกระแส stderr /dev/nullไป

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

$MY_DIRนอกจากนี้ทราบว่าผมเพิ่มอัญประกาศรอบ ด้วยวิธีนี้คำสั่งจะไม่ล้มเหลวหาก$MY_DIRมีช่องว่าง

หากคุณกำลังใช้เปลือกที่ทันสมัยเช่นทุบตีคุณควรใช้$( )เปลือกจับแทนการตีกลับ คุณควรพิจารณาเปลี่ยนสไตล์ของตัวแปรของคุณ โดยทั่วไปคุณควรหลีกเลี่ยงการใช้ชื่อตัวแปรตัวพิมพ์ใหญ่ทั้งหมดในสคริปต์ สไตล์นั้นสงวนไว้สำหรับตัวแปรสงวนและตัวแปรด้านสิ่งแวดล้อม

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

นี่ไม่ใช่ b0rk หรือไม่หากไม่มีไฟล์?
Mel Boyce

จริงๆแล้ว: ได้ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basenameผล
Mel Boyce

@MelBoyce: ฉันได้เพิ่มเข้าไปในคำตอบของฉัน ขอบคุณ

ls เป็นเครื่องมือสำหรับการดูข้อมูลไฟล์แบบโต้ตอบ เอาต์พุตถูกจัดรูปแบบสำหรับมนุษย์และจะทำให้เกิดข้อบกพร่องในสคริปต์ ใช้ globs หรือค้นหาแทน เข้าใจว่าทำไม: mywiki.wooledge.org/ParsingLs
cinelli

@cinelli: นั่นเป็นเรื่องจริง ฉันแค่ตอบคำถาม

9

ในไพพ์ไลน์คำสั่งทั้งหมดจะเริ่มต้นและรันพร้อมกันไม่ใช่หนึ่งคำสั่งหลังจากนั้น ดังนั้นคุณต้องเก็บเอาท์พุทที่ไหนสักแห่ง

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

โปรดทราบว่ามันถือว่าชื่อไฟล์ไม่มีอักขระขึ้นบรรทัดใหม่ การใช้xargsยังหมายถึงปัญหาเกี่ยวกับอักขระว่างเปล่าเครื่องหมายอัญประกาศเดี่ยวและแบ็กสแลช การปล่อยตัวแปรที่ไม่ได้กล่าวถึงจะหมายถึงปัญหาเกี่ยวกับช่องว่างแท็บและอักขระตัวแทน ลืมจะหมายถึงมีปัญหากับชื่อไฟล์ที่เริ่มต้นด้วย---

ในการรับ basename ของไฟล์ที่เก่าที่สุดzshโดยไม่มีข้อ จำกัด ใด ๆ ในตัวอักขระ (หลีกเลี่ยงปัญหาเรื่องขนาดของอาร์กิวเมนต์ที่ จำกัด ไปยังคำสั่ง):

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

หากไม่มีการจับคู่คำสั่งนั้นจะล้มเหลวและยกเลิกสคริปต์ คุณยังสามารถทำสิ่งต่อไปนี้

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

ในกรณีนี้first_file_nameอาร์เรย์จะมี 1 องค์ประกอบหากมีการจับคู่หรือ 0 ถ้าไม่ จากนั้นคุณสามารถทำได้:

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

4

ค้นหาไฟล์ที่แก้ไขล่าสุดในไดเรกทอรี:

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"
}

การใช้งาน: latest [directory/path/ [.extension]]

แทนที่จะเรียกbasenameใช้ให้ใช้การขยายพารามิเตอร์

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

ในไดเรกทอรีที่มีเนื้อหาเหล่านี้:

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

เนื้อหาของตัวแปร base_fn จะเป็น: newest

หากต้องการใช้สิ่งนี้อย่างถูกต้องเพื่อตอบสนองวัตถุประสงค์ของคำขอของคุณ:

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

แก้ไข: เมื่อตรวจสอบคำถามฉันได้ตระหนักว่าlsคำสั่งในคำถามกำลังมองหาไฟล์ที่เก่าที่สุดในไดเรกทอรี ฟังก์ชั่นเดียวกันนี้สามารถเปลี่ยนชื่อเป็นoldestและมี[[ $file -ot $oldest ]] && oldest=$fileแทนเพื่อให้บรรลุผลเดียวกัน ขออภัยในความสับสนใด ๆ

สิ่งสำคัญที่ควรทราบคือคุณไม่ควรแยกวิเคราะห์ผลลัพธ์ของ ls ไม่เคย


โปรดทราบว่าตรงกันข้ามกับlsแนวทางที่ใช้หากมีการเชื่อมโยงเวลาในการแก้ไขของเป้าหมายของการเชื่อมโยงจะได้รับการพิจารณา (เพิ่ม-Lตัวเลือกที่lsจะได้รับพฤติกรรมเดียวกันที่นั่น)
Stéphane Chazelas

0

ฉันคิดว่าตัวเลือกที่ดีที่สุดที่นี่คือ:

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

หากไม่มีไฟล์ดังนั้นโค้ดส่งคืนของ ls คือ 2 แต่หากพบว่าไฟล์บางไฟล์จะเป็น 0


2
แทนที่จะเปรียบเทียบ$?กับคุณสามารถทำสิ่งนี้:0 if ls -rf $MY_DIR/FILE.*.xml ; then

นอกจากนี้คุณยังสามารถเปลี่ยนเส้นทางการส่งออกของ COMAND /dev/nullแรกที่ ls -rf $MY_DIR/FILE.*.xml &> /dev/null. ด้วยวิธีนี้ผู้ใช้จะไม่เห็นผลลัพธ์เพิ่มเติม
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.