2017-11-29 2 views
0

ssh를 통해 원격 서버에 전달하는 복잡한 명령이 있습니다. 파일을 압축 해제하고 두 번째 ssh 명령에서 이름 지정 구조와 확장명을 변경하려고합니다. 내가이 명령은 다음과 같습니다 분명히bash에서 인용 부호를 이스케이프 처리 (임베디드 awk)

ssh [email protected] "gzip -d /tmp/file.out-20171119.gz; echo file* | awk -F'[.-]' '{print $1$3".log"}'" 

은 "인쇄 문의 .LOG 부분 주위에 나를 생각 나는 파일 이름에서이 .out 부분을 제거하고 file20171119.log로 끝날 것입니다 실패. 결과적으로 문법에 대해 혼란 스럽거나 bash가 .log를 적절하게 해석하도록 구문에서 혼란스러워합니다.

+0

아카이브를 확장해야합니까? 당신이하고있는 모든 작업이 파일 이름을 가지고 작업한다면, 'bash' 매개 변수 확장으로 처리 할 수 ​​있습니다. 'f =/tmp/file.out-20171119.gz'이면'g = $ {f/.out- /}; g = $ {g #/tmp /}; g = $ {g/%. gz/.log}'해야합니다. – chepner

+0

아카이브에 .out 파일이 있습니다. 그것이 내가 기본적으로 이름을 바꾸려고하는 파일입니다. 여전히 적용될 수 있습니까? –

+0

같은 접근 방식입니다. 물론'f'의 값이 다르면 할당 된 값을'g'에 사용했던 정확한 패턴을 조정해야 할 수도 있습니다. – chepner

답변

2

가장 쉬운 방법은이 문제를 해결하는 것입니다. 커맨드 라인을 사용하기 위해 스크립트를 벗어나려고 노력하지 마라. stdin 대신에 그것을 전달하라.

ssh [email protected] bash -s <<'EOF' 
    gzip -d /tmp/file.out-20171119.gz 
    # note that (particularly w/o a cd /tmp) this doesn't do anything at all related to the 
    # line above; thus, probably buggy as given in the original question. 
    echo file* | awk -F'[.-]' '{print $1$3".log"}' 
EOF 

인용 된 히어 닥 - 하나 <<'EOF' 또는 <<\EOF 대신 <<EOF의 - 모든 쉘 확장없이 그대로 전달된다; 따라서 $1 또는 $3은 인용되지 않은 heredoc에서와 같이 호출하는 셸로 대체되지 않습니다.


회피 경로를 원하지 않는다면 쉘이 직접 인용 부호를 사용하게 할 수 있습니다. 예 :

external_function() { 
    gzip -d /tmp/file.out-20171119.gz 
    echo file* | awk -F'[.-]' '{print $1$3".log"}' 
} 

ssh [email protected] "$(declare -f external_function); external_function" 

declare -f은 기능 정의를 인쇄합니다. 이 기능을 말 그대로 SSH 명령에 넣으면 원격으로 실행됩니다.

+0

이것은 이상적으로 보입니다. 그러나 어떤 이유로 bash는 그 EOF에 대해 불평하고 있습니다. 그것은 예기치 않은 파일 끝에 이어지는'EOF '를 원한다고 말합니다. –

+0

진단하기 위해 실행되는 코드 *를 정확히 볼 필요가 있습니다. 마지막'EOF' (예를 들어, heredoc 종료)가 들여 쓰기되어 있다면, 예를 들어 문제가 있습니다. 그것이 시작되는 라인의 맨 처음에 있어야합니다. –

+0

@ user1943674, ...다시 말하면,'server1'의 이름을 제외하고는 아무 것도 변경하지 않고 여기 **에 주어진 것과 똑같은 코드 **로 버그를 얻었는지 확인하십시오. –

1

"을 이스케이프 처리해야 인용 문자열을 빨리 닫을 수 없습니다. 로컬 매개 변수 확장을 막으려면 awk 스크립트에서 $을 이스케이프해야합니다.

ssh [email protected] "gzip -d /tmp/file.out-20171119.gz; echo file* | awk -F'[.-]' '{print \$1\$3\".log\"}'" 
+0

지금 오류가 발생합니다 : bash -c unexpected '' '와 다른 오류를 찾고있는 동안 EOF : 구문 오류 : 예기치 않은 파일 끝 –

+0

인용문을 다시 확인하십시오. 나를 위해 작동합니다 (적어도,'gzip'을 변수 할당으로 바꾸고'file *'대신에 awk'에 그 값을 echo 할 때). – chepner

+0

아마도 열린 따옴표를 남겨 두었습니다. 즉, 적절한 'EOF'문자열을 건너 뛰었습니다. –

0

가장 가능한 이유는 (서버에서 root 홈 디렉토리의 내용을 표시하지 않는 한) 당신이 /tmp 디렉토리에 파일을 압축 해제하지만, root 집에 있어야 파일 이름을 awk가하는 먹이이다 예배 규칙서.

"\으로 이스케이프 시퀀스를 허용합니다. 그렇게 할 수있는 올바른 방법이 다음과 같은 명령이 서버 시스템에서 쉘을 실행 의미 (당신이 당신의 질문에 쓴 것처럼)

ssh [email protected] "gzip -d /tmp/file.out-20171119.gz; echo file* | awk -F'[.-]' '{print \$1\$3\".log\"}'" 

입니다. 당신은이 명령을 실행하는

gzip -d /tmp/file.out-20171119.gz; echo file* | awk - F'[.-]' '{print $1$3".log"}' 

, 첫 번째 /tmp/file.out-2017119.gz를 (이 /tmp에 gunzip 한 것으로, 을 조심) 해제 (gunzip)합니다. 그리고 두 번째 문제의 근원이 될 수 있습니다. 이름에 file으로 시작하는 로컬 디렉토리 (아마도 root 사용자 홈 디렉토리, 서버의 /root)에 모든 파일 을 반향 출력하고 다음 awk 명령으로 전달합니다.

일반적으로 명령을 로컬에서 테스트하고 로컬에서 작동 할 때 첫 번째 셸에서 구문 분석 한 후 이스케이프 처리되지 않는 모든 특수 문자를 이스케이프 처리합니다.

문제를 해결하는 또 다른 방법은 필터로 gzip(1)을 사용하는 것입니다 ... 그래서 당신은 그냥 출력 파일을 포맷하는 awk(1) 실행을 저장

ssh [email protected] "gzip -d </tmp/file.out-20171119.gz >file20171119.log" 

이런 식으로 출력 파일의 이름을 결정할 수 있습니다 . 또는 환경 변수의 날짜가있는 경우.

DATE=`date +%Y%m%d` 
ssh [email protected] "gzip -d </tmp/file.out-${DATE}.gz >file${DATE}.log" 

마지막으로, 나에게 몇 가지 조언을 줄 수 있도록 : 파일의 압축을 /tmp를 사용하지 마십시오. /tmp은 여러 개의 배포판에서 고속 임시 디렉토리로 사용됩니다. 일반적으로 램 기반, 너무 빠르지 만 제한된 공간이므로 로그 파일의 압축을 해제하면 램 기반 파일 시스템에 사용되는 커널의 메모리를 채울 수 있습니다. 이는 좋은 생각이 아닙니다. 또한 로그 파일은 일반적으로 많이 확장되며 /tmp은 로컬 시스템 일반 디렉토리입니다. 다른 사용자가 file<something>이라는 파일을 저장할 수 있으며 해당 파일과 충돌 할 수 있습니다 (명령에서와 같이 와일드 카드 패턴을 사용하여 검색하는 경우) 또한 일단 파일의 이름을 알면 환경 변수에 할당하고 그 변수를 사용하는 것이 일반적입니다. 따라서 파일 이름의 형식을 변경해야하는 경우 한 곳에서만 수행 할 수 있습니다.

관련 문제