원격 서버에서 파일을 검색하여 로컬 컴퓨터로 다시 전송하는 스크립트를 작성 중입니다. 먼저 둘러보기를 수행하여 어떤 문서를 가져와야 할지 알 수 있었으면 좋았을 것입니다.
현재 내가 찾은 일부 코드의 믹스인 getopts
및 출력 리디렉션을 사용하고 있습니다.여기.
내 연구에 따르면 ZSH 또는 Bash 함수에서 배열을 반환하는 것은 비현실적입니다. 이로 인해 반복하지 않고서는 이 스크립트를 작성하는 방법을 이해하기가 어렵습니다.
이것은 내 현재 스크립트입니다.
편집하다:일부 bashism을 zsh와 혼합한 점을 용서해 주십시오. 저는 zsh를 사용하여 이 스크립트를 작성하기 시작했지만 #!/bin/bash
나중에 zsh로 전환했습니다.
#!/usr/local/bin/zsh
RED='\033[0;31m'
NC='\033[0m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
dry_run=0
yesterday=1
# Establish -n flag means to do a dry run.
while getopts "ny:" flag; do
case "$flag" in
n) dry_run=1 ;;
y) yesterday=${OPTARG} ;;
*) echo 'error in command line parsing' >&2
exit 1
esac
done
shift $(($OPTIND-1))
# This is the folder I'm interested in getting files from
folder=${1:?"You must define a folder of interest"}
# Check to see if dry-run, if not proceed with copying the files over.
if [ "$dry_run" -eq 1 ]; then
print -Pn "\n%S%11F%{Initiating Dry-Run%}%s%f"
# SSH onto server and find the most recently updated folder.
# Then place that newest folder and folder of interest into the absolute file path.
# Then SSH again and use find with that file-path
# Return array of file paths
# TODO: **THIS IS THE SECTION I NEED TO REFACTOR INTO A FUNCTION**
bison_remote_files=($(
{
{
bison_latest_run=$(ssh -qn falcon1 'find /projects/bison/git/* -mindepth 0 -maxdepth 0 -type d -printf "%T@\t%f\n"' |
sort -t$'\t' -r -nk1,5 |
sed -n "$yesterday"p |
cut -f2-)
bison_remote_path=$(
echo $bison_latest_run |
awk -v folder="$folder" '{print "/projects/bison/git/"$1"/assessment/LWR/validation/"folder}')
ssh -qn falcon1 \
"find $bison_remote_path -type f -name '*_out.csv' -not -path '*/doc/*' 2>/dev/null" >&3 3>&-; echo "$?"
print -Pn "\n\n%U%B%13F%{Fetching data from:%}%u %B%12F%{ /projects/bison/git/${bison_latest_run}%}%b%f\n" >&2
} | {
until read -t1 ret; do
print -Pn "%S%11F%{.%}%s%f" >&2
done
exit "$ret"
}
} 3>&1))
# Maninpulate remote file paths to match the local machine directory
local_file_path=($(for i in "${bison_remote_files[@]}"; do
echo $i |
gsed -E "s|/projects/bison/git/bison_[0-9]{8}|$HOME/Documents/projects/bison|g"
done
))
# Loop through remote and local and show where they will be placed
for ((i=1; i<=${#bison_remote_files[@]}; i++)); do
print -P "\u251C\U2500%B%1F%{Remote File ->%}%b%f ${bison_remote_files[i]}"
print -P "\u251C\U2500%B%10F%{Local File ->%}%b%f ${local_file_path[i]}"
if [[ $i -lt ${#bison_remote_files[@]} ]]; then
print -Pn "\U2502\n"
else
print -Pn "\U2514\U2500\U2504\U27E2\n"
fi
done
# If it's not a dry run, grab all the files using scp
# This is the part I am stuck...
# All my defined variables are un-run in the scope above
# How do I craft a function (or something else) so I don't have to do all the above all over again?
else
printf "${YELLOW}Fetching Data from ${NC}(${GREEN}${bison_latest_run}${NC})${YELLOW}...${NC}\n"
for ((i=0; i<${#NEW_RFILEP[@]}; i++)); do
scp -qp mcdodyla@falcon1:"${NEW_RFILEP[i]}" "${LOCAL_FILEP[i]}"
# Check if scp was successful, if it was show green.
if [ ${PIPESTATUS[0]} -eq 0 ]; then
printf "${GREEN}File Created/Updated at:${NC} ${LOCAL_FILEP[i]}\n"
else
printf "${RED}Error Fetching File:${NC} ${NEW_RFILEP[i]}\n"
fi
done
printf "${YELLOW}Bison Remote Fetch Complete!${NC}\n"
fi
보시다시피 모든 데이터가 첫 번째 if 문 상황에 갇혀 있으므로 연습 실행을 원하지 않으면 모든 코드를 다시 실행해야 합니다. bash/zsh는 실제로 배열을 반환하지 않으므로 이 코드를 어떻게 리팩터링할 수 있습니까?
편집하다:사용 사례의 예는 다음과 같습니다.
> bfetch -n "HBEP"
Initiating Dry-Run...
Fetching data from: /projects/bison/git/bison_20190827
├─Remote File -> /projects/bison/git/bison_20190827/assessment/LWR/validation/HBEP/analysis/BK370/HBEP_BK370_out.csv
├─Local File -> /Users/mcdodj/Documents/projects/bison/assessment/LWR/validation/HBEP/analysis/BK370/HBEP_BK370_out.csv
│
├─Remote File -> /projects/bison/git/bison_20190827/assessment/LWR/validation/HBEP/analysis/BK363/HBEP_BK363_out.csv
├─Local File -> /Users/mcdodj/Documents/projects/bison/assessment/LWR/validation/HBEP/analysis/BK363/HBEP_BK363_out.csv
│
├─Remote File -> /projects/bison/git/bison_20190827/assessment/LWR/validation/HBEP/analysis/BK365/HBEP_BK365_out.csv
├─Local File -> /Users/mcdodj/Documents/projects/bison/assessment/LWR/validation/HBEP/analysis/BK365/HBEP_BK365_out.csv
답변1
모르겠어요 zsh
. 하지만:
stderr
1) 먼저 모든 "세션" 인쇄 문이 가 아닌 로 이동하는지 확인하세요 stdout
. 예:
print -Pn "\n%S%11F%{Initiating Dry-Run%}%s%f" >&2
다른 많은 것들이 있습니다.
2) 그들은 귀하의 scp
진술을 실행하지 않고 예를 들어 다음과 같이 실행합니다.printf
stdout
printf 'scp -qp mcdodyla@falcon1:"%s" "%s"\n' "${NEW_RFILEP[i]}" "${LOCAL_FILEP[i]}"
여기에는 다음이 포함됩니다.모두cp
, , 등 파일 시스템을 수정하는 명령문 입니다 rm
. 귀하의 스크립트를 간략히 조사한 결과 이것이 저를 놀라게 한 유일한 것입니다. 그러나 귀하는 귀하의 코드를 나보다 더 잘 알고 있습니다.rsync
mkdir
touch
scp
코드를 다시 확인하고 모든 fs 수정("되돌릴 수 없음") 명령이 printf
's로 변환되는지 세 번 확인하세요. 당신은 그것의 어떤 것도 놓치고 싶지 않습니다.
이제 스크립트를 올바르게 변환했는지 테스트하려면 스크립트를 실행하고 삭제하세요 stderr
.
./myscript 2>/dev/null
stdout
이는 스크립트에만 표시되어야 합니다 .
당신은 보장해야합니다모두출력은 유효한 쉘 구문입니다. 모든 정보 메시지는 으로 전송되어야 하며 stderr
모든 "조치" 설명은 printf
으로 전송되어야 합니다 stdout
. 여전히 일부 정보 메시지가 스크립트에 누출되어 있는 경우 stdout
돌아가서 스크립트를 다시 편집하고 인쇄 문이 리디렉션되는지 확인하세요 >&2
.
stderr
정보 메시지를 에 보냈고 실제 작업을 에 보냈다는 사실을 명확하게 입증하면 stdout
변환이 완료됩니다.
테스트 실행을 수행하려면 다음 스크립트를 실행하세요.
./myscript
실제로 작업을 수행하려면 스크립트를 다시 실행하고 stdout
셸에 파이프하세요.
./myscript | zsh -v
답변2
나는 스크립팅에 능숙하지 않고 다른 쉘이 무엇을하는지 모릅니다.
그러나 최종 결과로 모든 코드를 다시 반복해야 한다면 m4와 같은 매크로 프로세서에서 코드를 빌드하고 m4 프로세서를 사용하여 소스 코드를 완전한 스크립트로 확장할 수 있습니다.
예를 들어, 배열 없이 어셈블리 언어로 작성하지만 주소를 반복해야 하는 경우 고정 주소에 일부 매크로 변수를 사용하여 루틴을 한 번 작성하고 m4 처리 후 매크로 파일에 '배열' 및 for 루프를 정의할 수도 있습니다. , 하나는 완전한 복제 소스를 갖게 됩니다.
어쩌면 여기서 비슷한 일을 할 수 있을까요? 아니면 쓸모없는 아이디어일 수도 있습니다. 그냥 생각입니다.