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
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í (sshopt -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 zkusilfind
a stále selhával. Myslím, že kvůli exportu, který řekla Dani.
shopt -s nullglob
.FILES=
ls * .zip; for fname in "${FILES}"...
, ale funguje podle očekávání sfor fname in *.zip ; do....
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ář.ls
vyhnout se: Proč ne analyzovatls
? ; podívejte se také na odkaz v horní části této stránky na článek BashGuide ' s ParsingLs .