Konečně se mi podařilo vyřešit problém, se kterým jsem se potýkal několik týdnů. Ke vzdálenému spouštění příkazů používám SSH s „autorizovanými klíči“. Všechno je v pořádku, kromě případů, kdy to dělám ve smyčce while. Cyklus se ukončí po dokončení jakékoli iterace pomocí příkazu ssh.
Dlouho jsem si myslel, že jde o nějaký druh ksh podivnosti, ale nyní jsem zjistil, že bash se ve skutečnosti chová identicky.
Malý ukázkový program pro reprodukci problému. Toto je odvozeno od větší implementace, která pořizuje snímky a replikuje je mezi uzly v clusteru.
#!/bin/bash
set -x
IDTAG=".*zone"
MARKER="mark-$(date +%Y.%m.%d.%H.%M.%S)"
REMOTE_HOST=sol10-target
ZFSPARENT=rpool
ssh $REMOTE_HOST zfs list -t filesystem -rHo name,mounted $ZFSPARENT | grep "/$IDTAG " > /tmp/actionlist
#for RMT_FILESYSTEM in $(cat /tmp/actionlist)
cat /tmp/actionlist | while read RMT_FILESYSTEM ISMOUNTED
do
echo ${RMT_FILESYSTEM}@${MARKER}
[ "$ISMOUNTED" = "yes" ] && ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER}
echo Remote Command Return Code: $?
done
(Všimněte si, že ve vyhledávacím výrazu grep je znak TAB podle definice chování volby „-H“ v seznamu zfs.)
Můj vzorek má nějaké souborové systémy ZFS pro kořen, kde všechny „zóny“ mají svůj kořenový souborový systém na datové sadě s názvem podobně jako
POOL/zones/app1zone
POOL/zones/group2/app2zone
atd.
Výše uvedená smyčka by měla vytvořit snímek pro každou z vybraných datových sad, ale místo toho funguje pouze s první a poté se ukončí.
Že program najde správný počet datových sad, lze snadno potvrdit kontrolou souboru „/tmp/actionlist“ poté, co skript existuje.
Pokud je příkaz ssh nahrazen například příkazem echo, pak smyčka prochází všemi vstupními řádky. Nebo můj oblíbený – před problematický příkaz přidejte „echo“.
Pokud místo toho použiji smyčku for, pak to také funguje, ale kvůli potenciální velikosti seznamu datových sad by to mohlo způsobit problémy s maximální rozšířenou délkou příkazového řádku.
Nyní jsem si na 99,999 % jistý, že problémy mi dělají pouze smyčky s příkazy ssh!
Všimněte si, že iterace, ve které je spuštěn příkaz ssh, je dokončena! Je to, jako by se data vložená do smyčky while náhle ztratila... Pokud prvních několik vstupních řádků neprovede příkaz ssh, pak smyčka pokračuje, dokud skutečně nespustí příkaz SSH.
Na svém notebooku, kde to testuji, mám dva virtuální počítače Solaris 10 pouze se dvěma nebo třemi ukázkovými datovými sadami, ale totéž se děje na velkých systémech SPARC, kde to má být spuštěno, a existuje mnoho datových sad.
Související:Jak změnit cron shell (sh na bash)?Přijatá odpověď:
SSH může číst ze standardního vstupu a požírat váš seznam akcí. Zkuste přesměrovat standardní vstup ssh na /dev/null:
ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER} </dev/null
Obecně platí, že při spouštění příkazů, které mohou rušit standardní vstup pod while read
-stylová smyčka, ráda zabalím celé tělo smyčky do rovnátek:
cat /tmp/uuoc | while read RMT_FILESYSTEM ISMOUNTED
do {
echo ${RMT_FILESYSTEM}@${MARKER}
[ "$ISMOUNTED" = "yes" ] && ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER}
echo Remote Command Return Code: $?
} < /dev/null; done