2013-12-16 22 views
11

Po pierwsze, w mojej obronie: Używam tylko csh, ponieważ moja grupa ma lot ze starszej wersji csh. Wykonujemy programowanie naukowe; niektórzy ludzie najwyraźniej nauczyli się używać csh w czasach SunOS/Solaris i nie poddawali się pomimo przejścia na Linuksa/bash i pomimo (oczywistej) IMHO przewagi tego ostatniego. Po drugie, przepraszam, jeśli jest to najczęściej zadawane pytanie, ale nie znalazłem odpowiedzi za pośrednictwem SO lub ogólnie googlowałem, a ja poświęciłem trochę więcej wysiłku obu.Jak przekazać tablicę numeryczną z bash do csh

takiej sytuacji:

Chcę jechać z bash niektórych starszych CSH skryptów, jako pierwszy krok w kierunku [przepisywanie, usuwając] ten ostatni. bash-> csh działa dobrze dla skalarnych zmiennych środowiskowych ("envvars"), ponieważ mogę je wyeksportować z bashu i odczytać je z csh zgodnie z oczekiwaniami.

Nie tablice, jednak ... poniżej Chris J. Kiick's answer poniżej! Poniższy przykład został zaktualizowany w celu uwzględnienia odpowiedzi Kiick i wyników, które generuje. Umieścić następujące 2 pliki w tym samym katalogu, ...

array_writer.sh

#!/usr/bin/env bash 
### Test writing an array, passing it to csh, and reading it there. 

THIS="$0" 
THIS_DIR="$(readlink -f $(dirname ${THIS}))" 
THIS_FN="$(basename ${THIS})" 
MESSAGE_PREFIX="${THIS_FN}:" 
ERROR_PREFIX="${MESSAGE_PREFIX} ERROR:" 

PARTNER_FN='array_reader.csh' 
PARTNER_DIR="${THIS_DIR}" 
PARTNER_FP="${PARTNER_DIR}/${PARTNER_FN}" 

export YEAR='2007' 
# month-related arrays for ${YEAR} 
declare -a BDOM=(0 31 59 90 120 151 181 212 243 273 304 334) # 0-based-Julian of first day of each month 
declare -a MDAY=(31 28 31 30 31 30 31 31 30 31 30 31) # days in each month, length=12 

echo -e "${MESSAGE_PREFIX} YEAR='${YEAR}':" 
# start debugging 
# use subshell for IFS 
(IFS=',' ; echo -e "\tBDOM=${BDOM[*]}") 
(IFS=',' ; echo -e "\tMDAY=${MDAY[*]}") 
# end debugging 

### Direct export of arrays fails, but this works! 
### Note it actually exports a string: see handling in partner 
echo -e "${MESSAGE_PREFIX} about to call ${PARTNER_FP}:\n" 
# from https://stackoverflow.com/a/20625229/915044 
bdom=${BDOM[*]} mday=${MDAY[*]} ${PARTNER_FP} 
if [[ $? -ne 0 ]] ; then 
    echo -e "\n${ERROR_PREFIX} failed or not found\n" 
else 
    echo -e "\n${MESSAGE_PREFIX} ${PARTNER_FP} returned successfully" 
fi 

array_reader.csh

#!/bin/csh -f 
### Test reading an array written from bash. 

set THIS="$0" 
# set THISDIR="$(readlink -f $(dirname ${THIS}))" # fails! 
set THIS_DIRNAME=`dirname ${THIS}` 
set THIS_DIR=`readlink -f ${THIS_DIRNAME}` 
set THIS_FN=`basename ${THIS}` 
set MESSAGE_PREFIX="${THIS_FN}:" 
set ERROR_PREFIX="${MESSAGE_PREFIX} ERROR:" 

if ($?bdom) then 
    # Gotta convert passed string into a "real" csh array 
    set bdom_array = ($bdom) 
    echo ${MESSAGE_PREFIX} found export=bdom, size=$#bdom_array":" 
    printf "\t"   # continue on same line 
    foreach item ($bdom_array) 
    printf "%d," $item # ditto 
    end 
    echo "" # newline to end the array-printing line 
else 
    echo "${ERROR_PREFIX} no export=bdom" 
    exit 2 
endif 

echo "" # separate reports 

if ($?mday) then 
    set mday_array = ($mday) 
    echo ${MESSAGE_PREFIX} found export=mday, size=$#mday_array":" 
    printf "\t" 
    foreach item ($mday_array) 
    printf "%d," $item 
    end 
    echo "" # newline to end the array-printing line 
else 
    echo "${ERROR_PREFIX} no export=mday" 
    exit 3 
endif 

exit 0 

... potem, z muszli, do ...

$ /path/to/array_writer.sh 
array_writer.sh: YEAR='2007': 
     BDOM=0,31,59,90,120,151,181,212,243,273,304,334 
     MDAY=31,28,31,30,31,30,31,31,30,31,30,31 
array_writer.sh: about to call /path/to/array_reader.csh: 

array_reader.csh: found export=bdom, size=12: 
     0,31,59,90,120,151,181,212,243,273,304,334, 

array_reader.csh: found export=mday, size=12: 
     31,28,31,30,31,30,31,31,30,31,30,31, 

array_writer.sh: /path/to/array_reader.csh returned successfully 
+1

ciekawe pytanie i wyraźnie wydałeś czasu na to, ale czy naprawdę musimy to wszystko ? Czy nie możemy udowodnić problemu w 2-4 linijkach każdego basha i csh? Nie możesz zredukować tego do prostszego przypadku testowego? Powodzenia! – shellter

+0

@shellter to już pomijane ze znacznie większego skryptu, który debuguję, przepraszam. – TomRoche

Odpowiedz

3

Jestem nie zaznajomieni z tablicami w csh, ale wydaje się dość łatwe eksportowanie:

w bash.

bdom=${BDOM[*]} mday=${MDAY[*]} ${PARTNER_FP} 

Nie trzeba komendę "env", bash został zbudowany, że w

Aby $ bdom na listę słów, zamiast pojedynczego ciągu, użyj(). w csh:

set bdom_array = ($bdom) 
+0

To działa! z wyjątkiem jednej irytacji z rozmiarem tablicy, której nie rozumiem - bez wątpienia z powodu mojej niewiedzy dotyczącej csh. Biorąc to pod uwagę, jest to irytacja, którą mogę zignorować, a twoja odpowiedź jest teraz częścią tego pytania. – TomRoche

+0

właśnie zorientowali się, że rozdrażnienie rozmiaru tablicy, dzięki. – TomRoche

+0

@TomRoche Powodem jest, że '$ bdom' nie jest _array_, ale _string_ (zdarza się, że zawiera listę słów i zachowuje się podobnie do tablicy w pewnych sytuacjach, na przykład z' foreach'). Jak zaznacza @rici: obecnie można eksportować tylko ciągi, a nie tablice (jawnie przez 'env' lub' export' lub przez niejawne 'env' jak w tym rozwiązaniu). '$ # someVar' w' csh' po prostu wypisuje wartość zmiennej, jeśli zmienna jest skalarem; tylko oryginalne zmienne tablicowe zwracają liczbę elementów. – mklement0

1

bash nie pozwala tablic eksportowych. ("Jeszcze", chociaż od dłuższego czasu jest "jeszcze".) Nie jest więc tak, że występuje problem z eksportowaniem tablic z bash do csh. Nie można również eksportować ich z bash do bash. (O ile mi wiadomo, od csh do csh.)

Tak naprawdę nie ma wielkiego rozwiązania. Możesz użyć formatu printf '%q', aby wypisać elementy w formacie, który może być eval 'd, ale musisz to zrobić za każdym razem, gdy zmieniasz element tablicy lub przynajmniej za każdym razem, gdy będziesz musiał zaimportować w podpowłokę. Ponadto, bash 's printf niekoniecznie eksportuje wartości w formacie zrozumiałym dla csh.

0

Jak zaznacza @rici, bash nie obsługuje eksportu tablic - ani z export, ani z env - i nie ma solidnego sposobu obejścia tego problemu.

Powiedział, jeśli wiesz, że:

  • elementy tablicy zawierać żadnych spacji ani innych znaków, które wymagają uciekających
  • tablica nie zawiera żadnych elementów, które stało się ważne globbing wzory (np , '*')

następnie można spłaszczyć tablice na jednowierszowe, oddzielone spacjami listy i przekazać je w ten sposób.

W przykładzie:

W array_writer.sh:

# export array as word list, i.e.: 
# as single-line string with space-separated tokens 
export BDOM_LIST="${BDOM[@]}" 

W array_reader.csh:

# Convert word list back into array. 
set BDOM=($BDOM_LIST)