ls
원격 호스트의 for 루프에 파일이 없으면 모든 것이 정상이지만 변수를 캡처하고 각 파일을 시도하면 변수 ls
가 echo
확장되지 않았거나 값이 없기 때문에 실패합니다.
내가 말하고 싶은 건:
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 할당을 명시적으로 끄기 위해 -T
with를 사용합니다.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
완전히 중복됩니다.
$(…)
솔직히 이것은 현재 대상 호스트 대신 로컬로 실행 되고 있기 때문에 전체 문제를 해결합니다 .