Bir komutun çıkışını başarılı olursa iletin


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

İkinci komutu ( head -1) yalnızca ilk komut başarılı olduğunda yürütmek istedim . Bu komutu nasıl geliştirebilirim?


Başarılı demekle ne demek istiyorsun? lsbaşarısız olmaz.
Matteo

2
Ancak eşleşen dosya yoksa glob başarısız olabilir.
tripleee

Yanıtlar:


8

Bunu dene:

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

Bayrağın iletilmesi xargs, -ryalnızca basenamestandart girdiden ( head -1) en az bir öğe okunduğunda çalışmasına neden olur .

head -1 yayınlanacak, ancak herhangi bir çıktı görmeyecek veya yakalamayacaksınız.

Ayrıca, kullanıcının herhangi bir hata çıktısı görmesini istemiyorsanız, 'stderr akışını' lsadresine yönlendirebilirsiniz .ls/dev/null

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

Ayrıca, içine tırnak işaretleri eklediğimi unutmayın $MY_DIR. Bu şekilde, $MY_DIRboşluklar varsa komut başarısız olmaz .

Eğer bash gibi modern bir $( )kabuk kullanıyorsanız, ters tırnaklar yerine bir yakalama kabuğu kullanmalısınız. Değişkenlerinizin stilini de değiştirmeyi düşünmelisiniz. Genellikle komut dosyalarında büyük harfli değişken adları kullanmaktan kaçınmalısınız. Bu stil genellikle ayrılmış ve çevresel değişkenler için ayrılmıştır.

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

Hiçbir dosya yoksa bu b0rk değil mi?
Mel Boyce

Aslında ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basenameçalışır.
Mel Boyce

@MelBoyce: Bunu cevabıma ekledim. Teşekkürler.

ls etkileşimli dosya bilgilerine bakmak için bir araçtır. Çıktıları insanlar için biçimlendirilmiştir ve komut dosyalarında hatalara neden olur. Globs kullanın veya onun yerine bulun. Neden anlayın: mywiki.wooledge.org/ParsingLs
cinelli

@cinelli: Bu doğru. Sadece soruyu cevaplıyordum.

9

Bir boru hattında, tüm komutlar birbiri ardına değil, aynı anda başlatılır ve çalıştırılır. Bu nedenle çıktıyı bir yerde saklamanız gerekir.

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

Dosya adlarının yeni satır karakterleri içermediğini varsaydığını unutmayın. Kullanmak xargs, boş karakterler, tek ve çift tırnak işaretleri ve ters eğik çizgilerle ilgili sorunlar anlamına da gelir. Değişkenleri tırnaksız bırakmak boşluk, sekme ve joker karakterlerle ilgili sorunlar anlamına gelir. Unutmak --, dosya adlarıyla başlayan sorunlar anlamına gelir -.

zshKarakterler üzerinde bu kısıtlamalardan herhangi biri olmadan en eski dosyanın taban adını almak için (ayrıca bir komuta ilişkin argümanların sınırlı boyutunun sorununu da önler):

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

Eşleşme yoksa, bu komut başarısız olur ve komut dosyasını iptal eder. Ayrıca şunları da yapabilirsiniz:

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

Bu durumda first_file_namedizi, bir eşleşme varsa 1 öğe veya yoksa 0 öğesi içerir. Daha sonra şunları yapabilirsiniz:

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

4

En son değiştirilen dosyayı bir dizinde bulun:

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

Kullanımı: latest [directory/path/ [.extension]]

Seslenmek yerine basenameparametre genişletmeyi kullanın.

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

Bu içeriğe sahip bir dizinde:

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

Base_fn değişkeninin içeriği: newest

Bunu isteğinizin amacına uygun olarak kullanmak için:

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: sorunun gözden geçirilmesi üzerine, söz konusu lskomut bir dizindeki en eski dosyayı aradığını fark ettim . aynı işlev yeniden adlandırılabilir oldestve [[ $file -ot $oldest ]] && oldest=$filebunun yerine aynı etkiyi elde edebilir. herhangi bir karışıklık için özür dileriz.

dikkat edilmesi gereken önemli bir nokta, kesinlikle, hiçbir koşulda insanlık içinde, ls çıktısını ayrıştırmamalısınız. asla.


lsTabanlı yaklaşımların aksine , sembolik bağlantılar varsa, sembolik düğmelerin hedefindeki değişiklik süresinin dikkate alınacağına dikkat edin ( orada aynı davranışı elde etme -Lseçeneğini ekleyin ls).
Stéphane Chazelas

0

Burada en iyi seçenek olduğunu düşünüyorum:

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

dosya yoksa, ls dönüş kodu 2'dir, ancak bazı dosya bulursa 0 olacaktır.


2
Bunun yerine karşılaştırmanın $?Against 0, bunu yapabilirsiniz: if ls -rf $MY_DIR/FILE.*.xml ; then.

Ayrıca, ilk kodun çıktısını konumuna yönlendirebilirsiniz /dev/null. ls -rf $MY_DIR/FILE.*.xml &> /dev/null. Bu şekilde, kullanıcı ekstra çıktıyı görmez.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.