Am crezut că acest lucru ar fi simplu – dar se dovedește mai complex decât mă așteptam.
Vreau să iterez prin toate fișierele unui anumit tip dintr-un director, așa că scriu acest lucru:
#!/bin/bash for fname in *.zip ; do echo current file is ${fname} done
Acest lucru funcționează atâta timp cât există cel puțin un fișier care se potrivește în director. Cu toate acestea, dacă nu există fișiere potrivite, obțin acest lucru:
current file is *.zip
Am încercat apoi:
#!/bin/bash FILES=`ls *.zip` for fname in "${FILES}" ; do echo current file is ${fname} done
În timp ce corpul buclei nu se execută atunci când nu există fișiere, primesc o eroare de la ls:
ls: *.zip: No such file or directory
Cum scriu un buclă care nu gestionează în mod curat niciun fișier care se potrivește?
Comentarii
Răspunde
În bash
, puteți seta opțiunea nullglob
astfel încât un model care nimeni nu „dispare”, mai degrabă decât tratat ca un șir literal:
shopt -s nullglob for fname in *.zip ; do echo "current file is ${fname}" done
În scriptul shell POSIX, trebuie doar să verificați dacă fname
există (și în același timp cu [ -f ]
, verificați dacă este un fișier obișnuit (sau link simbolic către un fișier obișnuit) și nu alte tipuri precum directorul / fifo / dispozitiv .. .):
for fname in *.zip; do [ -f "$fname" ] || continue printf "%s\n" "current file is $fname" done
Înlocuiți [ -f "$fname" ]
cu [ -e "$fname" ] || [ -L "$fname ]
dacă doriți să parcurgeți toate fișierele (care nu sunt ascunse) al căror nume se termină cu .zip
, indiferent de tipul lor.
Înlocuiți *.zip
cu .*.zip .zip *.zip
dacă doriți să luați în considerare și fișierele ascunse al căror nume se termină cu .zip
.
Comentarii
-
shopt -s nullglob
nu a funcționat pentru eu pe Ubuntu 17.04, dar[ -f "$fname" ] || continue
a funcționat bine. - @koppor Se pare că nu folosiți '
bash
. - +1 pentru o soluție POSIX.
Răspuns
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
Într-un comentariu aici menționați invocarea unei funcții …
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 *
Răspuns
Utilizați găsi
export -f myshellfunc find . -mindepth 1 -maxdepth 1 -type f -name "*.zip" -exec bash -c "myshellfunc "$0"" {} \;
TREBUIE să exportați funcția shell cu export -f
pentru ca acest lucru să funcționeze. Acum find
execută bash
care execută funcția dvs. de shell și rămâne doar la nivelul actual al dir.
Comentarii
- Care se repetă prin subdirectoare și vreau să invoc o funcție bash (nu script) pentru potriviri.
- @symcbean I ' a fost editat pentru a se limita la direcția unică și a gestiona funcțiile bash
Răspuns
În schimb of:
FILES=`ls *.zip`
Încercați:
FILES=`ls * | grep *.zip`
În acest fel, dacă ls eșuează (care este face în cazul dvs.) va grep ieșirea eșuată și va reveni ca o variabilă necompletată.
current file is <---Blank Here
Puteți adăuga o logică la aceasta pentru a face să revină „Nu Fișier găsit „
#!/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
În acest fel, dacă comanda anterioară a reușit (a ieșit cu o valoare 0), atunci va imprima fișierul curent, altfel va imprima„ Nu Fișiere găsite „
Comentarii
- I thi nk, este o idee proastă să mai adăugați un proces (
grep
) decât să încercați să remediați problema utilizând un instrument mai bun (find
) sau modificarea setării relevante pentru soluția curentă (cushopt -s nullglob
) - Conform comentariului OP ' în postarea lor originală
shopt -s nullglob
nu funcționează. Am încercatfind
în timp ce mi-am verificat răspunsul și nu a reușit. Cred că din cauza exportului a spus Dani.
shopt -s nullglob
înainte de a rula bucla for.FILES=
ls * .zip; for fname in "${FILES}"...
dar funcționează așa cum era de așteptat cufor fname in *.zip ; do....
for file in *.zip
, nu`ls ...`
. @cuonglm ' sugestia este astfel încât*.zip
să se extindă la nimic atunci când modelul nu ' nu se potrivește cu orice fișier.ls
fără argumente listează directorul curent.ls
trebuie să fie în general evitat: De ce nu analizațils
? ; consultați, de asemenea, linkul din partea de sus a paginii către BashGuide ' s ParsingLs articol.