파일 리디렉션이 작동하지 않는 SSH 명령

파일 리디렉션이 작동하지 않는 SSH 명령

authorized_keys파일의 고유한 줄만 필요하므로 다음 명령의 결과를 원격 서버의 파일로 리디렉션하고 싶습니다.

ssh [email protected] awk '!seen[$0]++' /root/.ssh/authorized_keys

나는 성공하지 않고 다음을 시도했습니다.

ssh [email protected] "awk '!seen[$0]++' /root/.ssh/authorized_keys > /root/.ssh/authorized_keystemp"

ssh [email protected] "awk \'!seen[$0]++\' /root/.ssh/authorized_keys > /root/.ssh/authorized_keystemp"

ssh [email protected] '(awk \'!seen[$0]++\' /root/.ssh/authorized_keys > /root/.ssh/authorized_keystemp)'

내 Google이 실패하고 있습니다. 내가 뭘 잘못하고 있는지 알 수 있나요?

답변1

이것을 시도해 보십시오(내 컴퓨터에서 테스트했는데 제대로 작동하는 것 같습니다. 제거할 중복 항목은 없지만...).

ssh [email protected] "awk '!seen[\$0]++' /root/.ssh/authorized_keys > /root/.ssh/authorized_keystemp"

"에 백슬래시가 없어 -quote 시도가 작동하지 않아 과 $같이 $0확장됩니다 bash.

작은 따옴표를 사용한 시도는 'foo\'some thing\'foo'당신이 생각하는 것을 의미하지 않기 때문에 작동하지 않습니다. \- 이스케이프 문자는 작은따옴표로 묶인 문자열 내에서 해석되지 않습니다. 따라서 이것은 실제로 불균형 따옴표와 두 개의 인수입니다. 첫 번째는 이고 foo\some두 번째는 이지만 마지막 인수는 작은 따옴표로 묶인 새 문자열을 시작하기 thing'foo때문에 불완전합니다 .'

쉘 탈출은 고통스러울 수 있으며, 특히 이중 탈출은 더욱 그렇습니다. 셸 스크립트를 먼저 보낸 다음( 등을 사용하여) 실행하는 것이 sftpscp쉬운 경우가 많습니다 .

답변2

필요한 정보를 제공하는 DeRobert의 답변을 수락하겠습니다. 여전히 문제가 있었고 그것이 내 awk명령일지도 모른다고 생각하고 다른 방법으로 교체했습니다. 원격 서버의authorized_keys 파일에 고유한 항목만 포함되도록 하기 위해 제가 수행한 작업은 다음과 같습니다.

ssh [email protected] "sort /root/.ssh/authorized_keys | uniq > /root/.ssh/temp"
ssh [email protected] "mv -f /root/.ssh/temp /root/.ssh/authorized_keys"

답변3

쉘 확장 및 토큰화로부터 보호하기 위해 무언가를 인용하는 것에 대해 알아야 할 모든 것은 다음과 같습니다.

  1. 아포스트로피 사이에 아포스트로피를 제외한 모든 항목을 묶습니다. 예를 들어, do not가 됩니다 'do not'.
  2. 아포스트로피를 이스케이프하려면 백슬래시를 사용 '하세요 \'.
  3. 문자열을 아포스트로피와 기타 문자로 나누고 이전 2개의 규칙을 적용한 후 결과를 연결합니다. 예를 들어, don't가 됩니다 'don'\''t'.

이러한 일반 규칙을 적용하면 다음과 같이 질문의 명령을 올바르게 인용할 수 있습니다.

ssh [email protected] 'awk '\''!seen[$0]++'\'' /root/.ssh/authorized_keys > /root/.ssh/authorized_keystemp'

동일한 문자열을 참조하는 더 읽기 쉬운 방법이 있지만 이 방법은 일반적으로 적용 가능하며 올바른지 시각적으로 쉽게 확인할 수 있습니다.

나는 이 작업을 너무 자주 수행하기 때문에 이를 수행하기 위한 쉘 함수/스크립트를 작성했고 항상 그것을 사용했습니다. 여기있어:

#!/bin/sh -

# shellquote foo => foo
# shellquote foo&bar => 'foo&bar'
# shellquote foo'bar => 'foo'\''bar'
shellquote() {
  local input="$1"
  local output=""
  local backslash='\'
  local apostrophe="'"
  if [ -z "${input}" ]; then
    # Empty string => pair of apostrophes
    output="''"
  fi
  while [ -n "${input}" ]; do
    case "${input}" in
    "'"*)
      # Escape the apostrophe.
      output="${output}${backslash}${apostrophe}"
      input="${input#${apostrophe}}"
      ;;
    *"'"*)
      # Quote everything before the first apostrophe, and then escape
      # the apostrophe.
      output="${output}${apostrophe}${input%%${apostrophe}*}${apostrophe}${backslash}${apostrophe}"
      input="${input#*${apostrophe}}"
      ;;
    *[!+,./0-9:=@A-Z_a-z-]*)
      # There are no apostrophes, but at least one character needs quoting.
      # So quote the entire word.
      output="${output}${apostrophe}${input}${apostrophe}"
      input=""
      ;;
    *)
      # Nothing needs quoting. Output everything literally.
      output="${output}${input}"
      input=""
    esac
  done
  printf '%s' "${output}"
}

main() {
  local sep=''
  for arg; do
    printf '%s' "${sep}"
    shellquote "${arg}"
    sep=' '
  done
}

main "$@"

관련 정보