변수가 확장되도록 SSH를 통해 원격으로 for 루프를 실행하는 방법은 무엇입니까?

변수가 확장되도록 SSH를 통해 원격으로 for 루프를 실행하는 방법은 무엇입니까?

ls원격 호스트의 for 루프에 파일이 없으면 모든 것이 정상이지만 변수를 캡처하고 각 파일을 시도하면 변수 lsecho확장되지 않았거나 값이 없기 때문에 실패합니다.

내가 말하고 싶은 건:

IFS=$'\n'
servers=(
  blue
  green
  red
)
for i in ${servers[@]}; do 
   ssh $i "
     ls /dir/xyz_${i}*/details.txt
   "
done
/dir/xyx_blue0/details.txt 
/dir/xyz_blue1/details.txt
/dir/xyx_green2/details.txt 
/dir/xyz_green4/details.txt
/dir/xyx_red1/details.txt 
/dir/xyz_red8/details.txt

ls하지만 실제로는 파일에 대한 작업을 수행할 수 있도록 출력을 반복해야 하지만 변수는 확장되지 않습니다.

for i in ${servers[@]}; do 
   ssh $i "
     for i in $(ls /dir/xyz_${i}*/details.txt); do 
        echo $i
     done
   "
done
not found: /dir/xyx_blue*/details.txt 
not found: /dir/xyx_green*/details.txt 
not found: /dir/xyx_red*/details.txt 

$i원격 호스트에서 루프를 실행할 때 어떻게 확장합니까?

답변1

문제는 원격 서버에서 실행하려는 명령 대체가 로컬에서 실행된다는 것입니다. 이는 대체가 큰따옴표 안에 발생하기 때문입니다. 이는 로컬 쉘이 호출하기 전에 확장을 계산한다는 것을 의미합니다 ssh.

또한 출력을 읽는 ls것은 현명하지 않습니다 (참조:왜 `ls`를 구문 분석하지 *않나요*(그리고 어떻게 수행합니까)?).

대신에:

servers=(
  blue
  green
  red
)

for server in "${servers[@]}"; do
    ssh -T "$server" <<END_SCRIPT
shopt -s nullglob
for pathname in /dir/xyz_$server*/details.txt; do
    printf 'file path is "%s"\n' "\$pathname"
done
END_SCRIPT
done

이는 원격 서버로 전송되는 스크립트로 따옴표 없이 "here-document"를 사용합니다. 스크립트는 먼저 패턴이 파일 이름과 일치하지 않는 경우 내부 루프에서 루프를 방지하기 위해 nullglob쉘 옵션(원격 쉘이 이라고 가정 )을 설정합니다. bash그런 다음 현재 서버 이름으로 대체될 패턴을 반복합니다 /dir/xyz_$server*/details.txt.$server

그런 다음 루프는 어떤 파일 이름이 패턴과 일치하는지에 대한 짧은 메시지를 인쇄하고 코드는 변수 $pathname가 일치하지 않는지 확인합니다.현지의이스케이프하여 쉘 $.

$in은 이스케이프 $server되지 않으므로 우리가 원하는 로컬 셸에 의해 확장되지만 $in은 $pathname다음과 같이 이스케이프되어야 합니다.막다로컬 확장.

IFS기본값이 아닌 값을 설정할 필요가 없습니다 . 나는 당신이 배열 할당을 작성할 수 있도록 또는 다른 이유로 이 작업을 수행한다고 가정하지만 위의 코드 중 어느 것도 이를 요구하지 않습니다.

나는 의사 TTY 할당을 명시적으로 끄기 위해 -Twith를 사용합니다.ssh


할 수 있다필요하다고 생각되면 스크립트를 단일 문자열로 제공할 수도 있습니다.

servers=(
  blue
  green
  red
)

for server in "${servers[@]}"; do
    ssh "$server" "
shopt -s nullglob
for pathname in /dir/xyz_$server*/details.txt; do
    printf 'file path is \"%s\"\n' \"\$pathname\"
done"
done

이 경우 포함된 각 큰따옴표가 이스케이프되었는지 확인해야 합니다(그렇지 않으면 원격 쉘 스크립트를 구성하는 큰따옴표로 묶인 문자열이 종료됩니다).

답변2

반복하지 마십시오. ; for의 출력은 ls문자 그대로 *와일드카드의 용도이며 전체 사용은 ls완전히 중복됩니다.

$(…)솔직히 이것은 현재 대상 호스트 대신 로컬로 실행 되고 있기 때문에 전체 문제를 해결합니다 .

관련 정보