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 nullglob
fungerte ikke for meg på Ubuntu 17.04, men[ -f "$fname" ] || continue
fungerte 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 nullglob
ikke. Jeg prøvdefind
mens jeg bekreftet svaret mitt, og det sviktet stadig. Jeg tror på grunn av eksporttingen Dani sa.
shopt -s nullglob
fø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*.zip
utvides til ingenting når mønsteret ikke ' t samsvarer med en hvilken som helst fil.ls
uten argumenter viser den nåværende katalogen.ls
generelt skal være unngått: Hvorfor ikke analyserels
? ; se også lenken nær toppen av den siden til BashGuide ' s ParsingLs artikkel.