Azt hittem, hogy ez egyszerű lesz – de ez bonyolultabbnak bizonyul, mint vártam.
Meg akarom ismételni a könyvtárban lévő összes adott típusú fájlt, ezért ezt írom:
#!/bin/bash for fname in *.zip ; do echo current file is ${fname} done
Ez addig működik, amíg van legalább egy megfelelő fájl ot a könyvtárban. Ha azonban nincs megfelelő fájl, akkor ezt kapom:
current file is *.zip
Ezután megpróbáltam:
#!/bin/bash FILES=`ls *.zip` for fname in "${FILES}" ; do echo current file is ${fname} done
Bár a ciklus törzse nem hajt végre, ha nincsenek fájlok, hibaüzenetet kapok az ls-től:
ls: *.zip: No such file or directory
Hogyan írjak egy ciklus, amely tisztán nem kezel megfelelő fájlokat?
Megjegyzések
Válasz
A bash
mezőben beállíthatja a nullglob
beállítást úgy, hogy egy minta semmi nem felel meg “eltűnik”, ahelyett, hogy szó szerinti karakterláncként kezelné:
shopt -s nullglob for fname in *.zip ; do echo "current file is ${fname}" done
A POSIX shell szkriptben csak ellenőriznie kell, hogy fname
létezik (és egyidejűleg a [ -f ]
paranccsal, ellenőrizze, hogy ez egy normál fájl (vagy a normál fájlra mutató szimbólum), és nem más típusú, mint például a directory / fifo / device .. .):
for fname in *.zip; do [ -f "$fname" ] || continue printf "%s\n" "current file is $fname" done
Cserélje le a [ -f "$fname" ]
szót a [ -e "$fname" ] || [ -L "$fname ]
szóra át akarja hurkolni az összes (nem rejtett) fájlt, amelyek neve .zip
végződésű, függetlenül attól, hogy típusuk.
Cserélje le a *.zip
szót a .*.zip .zip *.zip
kifejezésre, ha azokat a rejtett fájlokat is figyelembe kívánja venni, amelyek neve .zip
.
Megjegyzések
-
shopt -s nullglob
nem működtek én az Ubuntu 17.04-en, de a[ -f "$fname" ] || continue
jól működött. - @koppor Úgy hangzik, mintha nem használnál ' valójában
bash
. - +1 a POSIX megoldáshoz.
Válasz
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
Itt egy megjegyzésben megemlít egy függvény meghívását …
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 *
Válasz
A keresés használata
export -f myshellfunc find . -mindepth 1 -maxdepth 1 -type f -name "*.zip" -exec bash -c "myshellfunc "$0"" {} \;
A shell függvényt a export -f
hogy ez működjön. Most find
végrehajtja a bash
parancsot, amely végrehajtja a shell funkciót, és csak az aktuális dir szinten marad.
Megjegyzések
- Ami alkönyvtárakon keresztül ismétlődik, és a mérkőzésekhez egy bash függvényt (nem szkriptet) szeretnék meghívni.
- @symcbean I ' szerkesztette, hogy korlátozódjon az egyes direk és a bash függvények kezelésére
Válasz
Ehelyett /
FILES=`ls *.zip`
Próbálkozzon:
FILES=`ls * | grep *.zip`
Így, ha az ls nem sikerül (amit nem a te esetedben), a sikertelen kimenetet fogja megkapni, és üres változóként tér vissza.
current file is <---Blank Here
Ehhez adhatsz hozzá logikát, hogy visszatérjen “Nem Fájl található “
#!/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
Így, ha az előző parancs sikeres volt (0-as értékkel lépett ki), akkor az aktuális fájlt nyomtatja, különben a” Nem ” Fájlok találhatók “
Megjegyzések
- I thi nk, rossz ötlet még egy folyamat hozzáadása (
grep
), ahelyett, hogy egy jobb eszközzel próbálnánk kijavítani a problémát (find
) vagy az aktuális megoldás vonatkozó beállításának módosítása (shopt -s nullglob
-vel) - Az OP ' s megjegyzése szerint eredeti bejegyzésükön a
shopt -s nullglob
nem működik. Megpróbáltam afind
-et, miközben ellenőriztem a válaszomat, és ez folyamatosan kudarcot vallott. Szerintem az export miatt Dani mondta.
shopt -s nullglob
-t a for ciklus futtatása előtt.FILES=
ls * .zip; for fname in "${FILES}"...
, de a várt módon működik afor fname in *.zip ; do....
`ls ...`
. A @cuonglm ' javaslata az, hogy a*.zip
semmivé táguljon, ha a minta nem ' nem illeszkedik semmilyen fájlhoz. Az argumentumok nélkülils
felsorolja az aktuális könyvtárat.ls
kimenetét elemezni. kerülve: Miért nem elemzils
? ; lásd még az oldal teteje közelében található linket a BashGuide ' s ParsingLs cikkre.