Jeg trodde dette ville være enkelt – men det viser seg å være mer komplisert enn jeg forventet.
Jeg vil gjenta alle filene av en bestemt type i en katalog, så jeg skriver dette:
#!/bin/bash for fname in *.zip ; do echo current file is ${fname} done
Dette fungerer så lenge det er minst én samsvarende fil i katalogen. Men hvis det ikke er noen samsvarende filer, får jeg dette:
current file is *.zip
Jeg prøvde:
#!/bin/bash FILES=`ls *.zip` for fname in "${FILES}" ; do echo current file is ${fname} done
Selv om løkken ikke utføres når det ikke er filer, får jeg en feil fra ls:
ls: *.zip: No such file or directory
Hvordan skriver jeg en loop som rent håndterer ingen samsvarende filer?
Kommentarer
Svar
I bash kan du stille inn nullglob slik at et mønster som samsvarer med ingenting som «forsvinner», i stedet for å bli behandlet som en bokstavelig streng:
shopt -s nullglob for fname in *.zip ; do echo "current file is ${fname}" done
I POSIX-skallskript bekrefter du bare at fname eksisterer (og samtidig med [ -f ], sjekk at det er en vanlig fil (eller symlink til vanlig fil) og ikke andre typer som katalog / fifo / enhet .. .):
for fname in *.zip; do [ -f "$fname" ] || continue printf "%s\n" "current file is $fname" done
Erstatt [ -f "$fname" ] med [ -e "$fname" ] || [ -L "$fname ] ønsker å løpe over alle (ikke-skjulte) filer hvis navn ender på .zip uansett deres type.
Erstatt *.zip med .*.zip .zip *.zip hvis du også vil vurdere skjulte filer hvis navn ender på .zip.
Kommentarer
-
shopt -s nullglobfungerte ikke for meg på Ubuntu 17.04, men[ -f "$fname" ] || continuefungerte bra. - @koppor Det høres ut som om du ikke ' ikke bruker
bash. - +1 for en POSIX-løsning.
Svar
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
I en kommentar her nevner du å påkalle en funksjon …
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 *
Svar
Bruk finn
export -f myshellfunc find . -mindepth 1 -maxdepth 1 -type f -name "*.zip" -exec bash -c "myshellfunc "$0"" {} \;
Du MÅ eksportere skallfunksjonen din med export -f for at dette skal fungere. Nå find utfører bash som utfører skallfunksjonen din, og forblir bare på gjeldende dir-nivå.
Kommentarer
- Som gjentas gjennom underkataloger, og jeg vil påkalle en bash-funksjon (ikke script) for kampene.
- @symcbean I ' har redigert for å begrense til enkelt dir og håndtere bash-funksjoner
Svar
I stedet av:
FILES=`ls *.zip`
Prøv:
FILES=`ls * | grep *.zip`
Denne måten hvis ls mislykkes (som det gjør i ditt tilfelle) vil det grep den mislykkede utgangen og returnere som en tom variabel.
current file is <---Blank Here
Du kan legge til noen logikk for å få den til å returnere «Nei Fil funnet «
#!/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
På denne måten hvis den forrige kommandoen lyktes (avsluttet med en 0-verdi), vil den skrive ut den nåværende filen, ellers vil den skrive ut» Nei Filer funnet «
Kommentarer
- I thi nk er det en dårlig ide å legge til en prosess til (
grep) i stedet for å prøve å løse problemet ved å bruke et bedre verktøy (find) eller endre relevant innstilling for den gjeldende løsningen (medshopt -s nullglob) - I følge OP ' s kommentar på deres opprinnelige innlegg fungerer
shopt -s nullglobikke. Jeg prøvdefindmens jeg bekreftet svaret mitt, og det sviktet stadig. Jeg tror på grunn av eksporttingen Dani sa.
shopt -s nullglobfør du kjører for loop.FILES=ls * .zip; for fname in "${FILES}"...men det fungerer som forventet medfor fname in *.zip ; do....for file in *.zip, ikke`ls ...`. @cuonglm ' sitt forslag er slik at*.ziputvides til ingenting når mønsteret ikke ' t samsvarer med en hvilken som helst fil.lsuten argumenter viser den nåværende katalogen.lsgenerelt skal være unngått: Hvorfor ikke analyserels? ; se også lenken nær toppen av den siden til BashGuide ' s ParsingLs artikkel.