bash iterovat seznam souborů, kromě případů, kdy je prázdný

Myslel jsem, že by to bylo jednoduché – ale ukazuje se to složitější, než jsem čekal.

Chci iterovat přes všechny soubory konkrétního typu v adresáři, takže píšu toto:

#!/bin/bash for fname in *.zip ; do echo current file is ${fname} done 

Toto funguje pokud existuje alespoň jeden odpovídající soubor v adresáři. Pokud však neexistují žádné odpovídající soubory, dostanu toto:

current file is *.zip 

Zkoušel jsem to:

#!/bin/bash FILES=`ls *.zip` for fname in "${FILES}" ; do echo current file is ${fname} done 

I když se tělo smyčky nespouští, když nejsou žádné soubory, zobrazí se mi chyba ls:

ls: *.zip: No such file or directory 

Jak mohu napsat smyčka, která čistě nezpracovává žádné odpovídající soubory?

Komentáře

  • Před spuštěním smyčky for přidejte shopt -s nullglob.
  • @cuolnglm: strašidelně to bude mít za následek vrácení názvu prováděcího skriptu namísto prázdného seznamu v tomto poli RHEL5 (bash 3.2.25), pokud ano FILES= ls * .zip ; for fname in "${FILES}"..., ale funguje podle očekávání s for fname in *.zip ; do....
  • použít for file in *.zip, ne `ls ...`. Návrh @cuonglm ' je takový, že *.zip se rozšiřuje na nic, když vzor ' neodpovídá žádnému souboru. ls bez argumentů uvádí aktuální adresář.
  • Tato otázka pojednává o tom, proč je obvykle třeba analyzovat výstup ls vyhnout se: Proč ne analyzovat ls? ; podívejte se také na odkaz v horní části této stránky na článek BashGuide ' s ParsingLs .
  • Možný duplikát Proč se můj skript škrtí mezerami nebo jinými speciálními znaky?

Odpovědět

V bash můžete nastavit možnost nullglob tak, aby vzor, který neodpovídá ničemu, co „zmizí“, místo aby bylo považováno za doslovný řetězec:

shopt -s nullglob for fname in *.zip ; do echo "current file is ${fname}" done 

Ve skriptu prostředí POSIX stačí ověřit, že fname existuje (a současně s [ -f ] zkontrolujte, zda se jedná o běžný soubor (nebo symbolický odkaz na běžný soubor), a nikoli jiné typy, jako je adresář / fifo / zařízení .. .):

for fname in *.zip; do [ -f "$fname" ] || continue printf "%s\n" "current file is $fname" done 

Nahraďte [ -f "$fname" ] řetězcem [ -e "$fname" ] || [ -L "$fname ] chcete vytvořit smyčku přes všechny (neskryté) soubory, jejichž název končí na .zip bez ohledu na jejich typ.

Pokud chcete také zvážit skryté soubory, jejichž název končí na iv, nahraďte *.zip znakem .*.zip .zip *.zip id = „2befeeca63″>

.

Komentáře

  • shopt -s nullglob nepracovali pro já na Ubuntu 17.04, ale [ -f "$fname" ] || continue fungoval dobře.
  • @koppor Zní to, jako byste ' ve skutečnosti nepoužívali bash.
  • +1 pro řešení POSIX.

Odpovědět

set ./* #set the arg array to glob results ${2+":"} [ -e "$1" ] && #if more than one result skip the stat "$1" printf "current file is %s\n" "$@" #print the whole array at once ###or### ${2+":"} [ -e "$1" ] && #same kind of test for fname #iterate singly on $fname var for array do printf "file is %s\n" "$fname" #print each $fname for each iteration done 

V komentáři zde zmiňujete vyvolání funkce …

file_fn() if [ -e "$1" ] || #check if first argument exists [ -L "$1" ] #or else if it is at least a broken link then for f #if so iterate on "$f" do : something w/ "$f" done else command <"${1-/dev/null}" #only fail w/ error if at least one arg fi file_fn * 

Odpověď

Použijte find

export -f myshellfunc find . -mindepth 1 -maxdepth 1 -type f -name "*.zip" -exec bash -c "myshellfunc "$0"" {} \; 

MUSÍTE exportovat svou funkci shellu pomocí export -f aby to fungovalo. Nyní find provede bash, který provede vaši funkci shellu, a zůstane pouze na aktuální úrovni adresáře.

Komentáře

  • Který se opakuje v podadresářích a chci pro zápasy vyvolat funkci bash (ne skript).
  • @symcbean I ' jsme upravili tak, aby se omezil na jediný adresář a zpracovával bash funkce

odpověď

místo toho z:

FILES=`ls *.zip` 

Zkuste:

FILES=`ls * | grep *.zip` 

Tímto způsobem, pokud ls selže (což ve vašem případě) bude grep chybný výstup a vrátí se jako prázdná proměnná.

current file is <---Blank Here 

K tomu můžete přidat nějakou logiku, aby se to vrátilo „Ne Soubor nalezen „

#!/bin/bash FILES=`ls * | grep *.zip` if [[ $? == "0" ]]; then for fname in "$FILES" ; do echo current file is $fname done else echo "No Files Found" fi 

Tímto způsobem, pokud předchozí příkaz uspěl (byl ukončen s hodnotou 0), vytiskne aktuální soubor, jinak by vytiskl“ Ne Nalezené soubory „

Komentáře

  • I thi nk je špatný nápad přidat jeden další proces (grep) místo pokusu o vyřešení problému pomocí lepšího nástroje (find ) nebo změna příslušného nastavení pro aktuální řešení (s shopt -s nullglob)
  • podle komentáře OP ' na jejich původním příspěvku shopt -s nullglob nefunguje. Při ověřování své odpovědi jsem zkusil find a stále selhával. Myslím, že kvůli exportu, který řekla Dani.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *