bash fájlok listájának iterálása, kivéve, ha üres

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

  • Add hozzá a shopt -s nullglob -t a for ciklus futtatása előtt.
  • @cuolnglm: kísértetiesen ez azt eredményezi, hogy ebben az RHEL5 mezőben (bash 3.2.25) üres lista helyett a végrehajtó szkript nevét adja vissza, ha FILES= ls * .zip ; for fname in "${FILES}"..., de a várt módon működik a for fname in *.zip ; do....
  • , nem `ls ...`. A @cuonglm ' javaslata az, hogy a *.zip semmivé táguljon, ha a minta nem ' nem illeszkedik semmilyen fájlhoz. Az argumentumok nélküli ls felsorolja az aktuális könyvtárat.
  • Ez a kérdés azt tárgyalja, hogy miért kell általában a ls kimenetét elemezni. kerülve: Miért nem elemzi ls? ; lásd még az oldal teteje közelében található linket a BashGuide ' s ParsingLs cikkre.
  • A (z) lehetséges másolata. Miért fojtja el a shell szkript a szóközt vagy más speciális karaktereket?

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 a find -et, miközben ellenőriztem a válaszomat, és ez folyamatosan kudarcot vallott. Szerintem az export miatt Dani mondta.

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük