Tein seuraavan komentosarjan:
# !/bin/bash # OUTPUT-COLORING red="\e[0;31m" green="\e[0;32m" NC="\e[0m" # No Color # FUNCTIONS # directoryExists - Does the directory exist? function directoryExists { cd $1 if [ $? = 0 ] then echo -e "${green}$1${NC}" else echo -e "${red}$1${NC}" fi } # EXE directoryExists "~/foobar" directoryExists "/www/html/drupal"
Skripti toimii, mutta minun vieressä kaiku, siellä on myös lähtö, kun
cd $1
epäonnistuu suorituksessa.
testscripts//test_labo3: line 11: cd: ~/foobar: No such file or directory
Onko tämä mahdollista kiinni?
Kommentit
Vastaa
Komentosarjasi muuttaa hakemistoja suorituksen aikana, mikä tarkoittaa, että se ei toimi sarja suhteellisia polkuja. Kommentoit myöhemmin, että halusit tarkistaa vain hakemiston olemassaolon, etkä kykyä käyttää cd
, joten vastausten ei tarvitse käyttää cd
ollenkaan. Tarkistettu. Käyttämällä tput
ja värejä kohteesta man terminfo
:
#!/bin/bash -u # OUTPUT-COLORING red=$( tput setaf 1 ) green=$( tput setaf 2 ) NC=$( tput setaf 0 ) # or perhaps: tput sgr0 # FUNCTIONS # directoryExists - Does the directory exist? function directoryExists { # was: do the cd in a sub-shell so it doesn"t change our own PWD # was: if errmsg=$( cd -- "$1" 2>&1 ) ; then if [ -d "$1" ] ; then # was: echo "${green}$1${NC}" printf "%s\n" "${green}$1${NC}" else # was: echo "${red}$1${NC}" printf "%s\n" "${red}$1${NC}" # was: optional: printf "%s\n" "${red}$1 -- $errmsg${NC}" fi }
(muokattu käyttää haavoittumattomampaa printf
ongelmallisen echo
sijasta, joka saattaa vaikuttaa tekstin pakosekvensseihin.)
Kommentit
- Se korjaa myös ongelmat (ellei xpg_echo ole päällä), kun tiedostonimet sisältävät taaksepäin viivamerkkejä.
Vastaa
Määritä set -e
-asetuksella exit-on-error-tila: jos yksinkertainen komento palauttaa nollasta poikkeavan tilan (mikä tarkoittaa vikaa), kuori poistuu.
Varo, että set -e
ei aina potkaise sisään. Testiasennoissa olevien komentojen annetaan epäonnistua (esim. if failing_command
, failing_command || fallback
). Alikuoren komennot johtavat vain alikuoresta poistumiseen, ei vanhempaan: set -e; (false); echo foo
näyttää foo
.
Vaihtoehtoisesti tai lisäksi bash (ja ksh ja zsh, mutta ei tavallinen sh), voit määrittää komennon, joka suoritetaan, jos komento palauttaa nollatilan, ERR
-loukulla, esim. trap "err=$?; echo >&2 "Exiting on error $err"; exit $err" ERR
. Huomaa, että sellaisissa tapauksissa kuin (false); …
, ERR-ansa suoritetaan alikuoressa, joten se ei voi aiheuttaa vanhemman poistumista.
Kommentit
- Kokeilin äskettäin vähän ja löysin kätevän tavan korjata
||
-käyttäytyminen, jonka avulla virheiden oikea käsittely voidaan tehdä helposti ilman ansoja. vastaukseni . Mitä mieltä olet menetelmästä? - @ sam.kozin En ’ t: lla on aikaa tarkistaa vastauksesi yksityiskohtaisesti, se näyttää periaatteessa hyvältä. Mitkä ovat kannettavuuden lisäksi ksh / bash / zsh: n edut ’ s ERR-ansaan?
- Ainoa hyöty on luultavasti yhdistettävyys, koska et ’ vaaraa korvata toisen ansan, joka oli asetettu ennen toiminnon suorittamista. Mikä on hyödyllinen ominaisuus, kun ’ kirjoittaa jonkin yleisen toiminnon, jonka hankit myöhemmin ja jota käytät muista skripteistä. Toinen etu saattaa olla täydellinen POSIX-yhteensopivuus, vaikka se ei olekaan niin tärkeää, koska
ERR
-pseudosignaalia tuetaan kaikissa pääkuorissa. Kiitos arvostelusta! =) - @ sam.kozin Unohdin kirjoittaa edelliseen kommenttiin: voit halutessasi lähettää tämän Code Review -palveluun ja lähettää linkki keskusteluhuoneessa .
- Kiitos ehdotuksesta, yritän seurata ’ se. En tiennyt ’ tienne Code Review -sovelluksesta.
Vastaa
@Gilles ”-vastauksen laajentaminen:
Itse asiassa set -e
ei toimi sisällä -komennot, jos käytät niiden jälkeen ||
-operaattoria, vaikka suoritatkin ne alikuoressa; esim. tämä ei toimi:
#!/bin/sh # prints: # # --> outer # --> inner # ./so_1.sh: line 16: some_failed_command: command not found # <-- inner # <-- outer set -e outer() { echo "--> outer" (inner) || { exit_code=$? echo "--> cleanup" return $exit_code } echo "<-- outer" } inner() { set -e echo "--> inner" some_failed_command echo "<-- inner" } outer
Mutta ||
-operaattoria tarvitaan estämään paluu ulkoisesta toiminnosta ennen puhdistusta.
Tämän korjaamiseen voidaan käyttää pientä temppua: Suorita sisempi komento taustalla ja sitten heti odota sitä.Sisäänrakennettu wait
palauttaa sisäisen komennon poistumiskoodin, ja nyt käytät ||
-kuvaketta , ei sisäistä toimintoa, joten set -e
toimii oikein jälkimmäisen sisällä:
#!/bin/sh # prints: # # --> outer # --> inner # ./so_2.sh: line 27: some_failed_command: command not found # --> cleanup set -e outer() { echo "--> outer" inner & wait $! || { exit_code=$? echo "--> cleanup" return $exit_code } echo "<-- outer" } inner() { set -e echo "--> inner" some_failed_command echo "<-- inner" } outer
Tässä on yleinen toiminto, joka perustuu tähän ajatukseen. Sen pitäisi toimia kaikissa POSIX-yhteensopivissa kuoreissa, jos poistat local
avainsanat, ts. korvaa kaikki local x=y
vain x=y
:
# [CLEANUP=cleanup_cmd] run cmd [args...] # # `cmd` and `args...` A command to run and its arguments. # # `cleanup_cmd` A command that is called after cmd has exited, # and gets passed the same arguments as cmd. Additionally, the # following environment variables are available to that command: # # - `RUN_CMD` contains the `cmd` that was passed to `run`; # - `RUN_EXIT_CODE` contains the exit code of the command. # # If `cleanup_cmd` is set, `run` will return the exit code of that # command. Otherwise, it will return the exit code of `cmd`. # run() { local cmd="$1"; shift local exit_code=0 local e_was_set=1; if ! is_shell_attribute_set e; then set -e e_was_set=0 fi "$cmd" "$@" & wait $! || { exit_code=$? } if [ "$e_was_set" = 0 ] && is_shell_attribute_set e; then set +e fi if [ -n "$CLEANUP" ]; then RUN_CMD="$cmd" RUN_EXIT_CODE="$exit_code" "$CLEANUP" "$@" return $? fi return $exit_code } is_shell_attribute_set() { # attribute, like "x" case "$-" in *"$1"*) return 0 ;; *) return 1 ;; esac }
Esimerkki käytöstä:
#!/bin/sh set -e # Source the file with the definition of `run` (previous code snippet). # Alternatively, you may paste that code directly here and comment the next line. . ./utils.sh main() { echo "--> main: $@" CLEANUP=cleanup run inner "$@" echo "<-- main" } inner() { echo "--> inner: $@" sleep 0.5; if [ "$1" = "fail" ]; then oh_my_god_look_at_this fi echo "<-- inner" } cleanup() { echo "--> cleanup: $@" echo " RUN_CMD = "$RUN_CMD"" echo " RUN_EXIT_CODE = $RUN_EXIT_CODE" sleep 0.3 echo "<-- cleanup" return $RUN_EXIT_CODE } main "$@"
Esimerkin suorittaminen:
$ ./so_3 fail; echo "exit code: $?" --> main: fail --> inner: fail ./so_3: line 15: oh_my_god_look_at_this: command not found --> cleanup: fail RUN_CMD = "inner" RUN_EXIT_CODE = 127 <-- cleanup exit code: 127 $ ./so_3 pass; echo "exit code: $?" --> main: pass --> inner: pass <-- inner --> cleanup: pass RUN_CMD = "inner" RUN_EXIT_CODE = 0 <-- cleanup <-- main exit code: 0
Ainoa asia, jonka sinun on oltava tietoinen tätä menetelmää käytettäessä, on, että kaikki Shell-muuttujien muutokset tehdään com: lta run
välitettävä mand ei siirry kutsutoimintoon, koska komento suoritetaan alikuoressa.
Vastaa
Et sano, mitä tarkoita catch
— -raportilla ja jatka; keskeytetäänkö jatkokäsittely?
Koska cd
palauttaa nollasta poikkeavan tilan epäonnistumisen yhteydessä, voit tehdä seuraavaa:
cd -- "$1" && echo OK || echo NOT_OK
Voit yksinkertaisesti poistua epäonnistumisesta:
cd -- "$1" || exit 1
Tai toista oma viesti ja lopeta:
cd -- "$1" || { echo NOT_OK; exit 1; }
Ja / tai estä cd
-virheen aiheuttama virhe:
cd -- "$1" 2>/dev/null || exit 1
Standardien mukaan komentojen tulisi laittaa virhesanomat STDERR: ään (tiedostokuvaaja 2). Siten 2>/dev/null
sanoo ohjaavan STDERR: n ”bit-bucketiin”, jonka /dev/null
tietää.
(älä unohda lainata muuttujiasi ja merkitä vaihtoehtojen loppu osioon cd
).
Kommentit
- @Stephane Chazelas-piste lainaa ja merkitse vaihtoehtojen loppu hyvin. Kiitos muokkauksesta.
Vastaa
Oikeastaan sinun tapauksessasi sanoisin, että logiikkaa voidaan parantaa.
CD: n sijasta ja tarkista sitten, onko sitä olemassa, tarkista onko se olemassa, siirry sitten hakemistoon.
if [ -d "$1" ] then printf "${green}${NC}\\n" "$1" cd -- "$1" else printf "${red}${NC}\\n" "$1" fi
Mutta jos tarkoituksena on hiljentää mahdolliset virheet, cd -- "$1" 2>/dev/null
, mutta tämä tekee sinusta jatkossa virheenkorjauksen vaikeammaksi. Voit tarkistaa if-testauksen liput osoitteessa: Bash jos dokumentaatio :
Kommentit
- Tämä vastaus ei onnistu lainaa muuttujaa
$1
ja epäonnistuu, jos muuttuja sisältää aihioita tai muita kuoren metahahmoja. Se ei myöskään tarkista, onko käyttäjällä lupacd
siihen. - Yritin itse asiassa tarkistaa, onko olemassa tietty hakemisto, ei välttämättä cd siihen . Mutta koska en tiennyt ’ en tiennyt paremmin, ajattelin, että CD-levylle yrittäminen aiheuttaisi virheen, jos sitä ei olisi, joten miksi et saisi sitä kiinni? En tiennyt ’ tiedä if [-d $ 1] että ’ tarkalleen mitä tarvitsin. Joten, kiitos paljon! (I ’ m käytin Java-ohjelmointia ja hakemiston tarkistamista if-lauseessa ei ole aivan yleistä Java-ohjelmassa)
test -d /path/to/directory
(tai bashissa[[ -d /path/to/directory ]]
) kertoo, onko tietty kohde hakemisto vai ei, ja se tekee sen hiljaa.cd
siihen.directoryExists
.