heredoc (EOF)에 echo -n과 비슷한 것이 있습니까?


12

서버에 대한 많은 유지 보수 스크립트를 생성하는 거대한 스크립트 팩토리 스크립트를 작성 중입니다.

지금까지 내가 한 줄에 작성해야 몇 줄 쓰기 echo -ne예를

echo -n "if (( " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null

# Generate exitCode check for each Server
IFS=" "
COUNT=0
while read -r name ipAddr
do
    if(($COUNT != 0))
    then
        echo -n " || " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
    fi

    echo -n "(\$"$name"_E != 0 && \$"$name"_E != 1)" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null

    COUNT=$((COUNT+1))

    JOBSDONE=$((JOBSDONE+1))
    updateProgress $JOBCOUNT $JOBSDONE
done <<< "$(sudo cat /root/.virtualMachines)"

echo " ))" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null

이것은 (구성 파일에 2 개의 서버가있는 경우) 코드를 생성합니다.

if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))

내가 작성하고 유지 관리하는 것이 더 낫다는 것을 알기 때문에 heredocs로 생성하는 코드의 인라인 작성이 필요하지 않은 다른 모든 코드 블록. 예를 들어 위 코드 후에 나머지는 다음과 같이 생성됩니다.

cat << EOF | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
then
    # Print out ExitCode legend
    echo " ExitCode 42 - upgrade failed"
    echo " ExitCode 43 - Upgrade failed"
    echo " ExitCode 44 - Dist-Upgrade failed"
    echo " ExitCode 45 - Autoremove failed"
    echo ""
    echo ""
fi
EOF

최종 코드 블록은

if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))
then
    # Print out ExitCode legend
    echo " ExitCode 42 - upgrade failed"
    echo " ExitCode 43 - Upgrade failed"
    echo " ExitCode 44 - Dist-Upgrade failed"
    echo " ExitCode 45 - Autoremove failed"
    echo ""
    echo ""
fi

내 질문
Heredoc echo -ne이 줄 끝 이 없는 것과 비슷한 방식으로 작동하는 방법이 있습니까?


1
sudo스크립트에 필요한 경우 잘못하고 있습니다 : 대신 전체 스크립트를 루트로 실행하십시오!
디저트

1
아니 그것은 다른 일을하고 있기 때문에 루트로 실행하고 싶지 않아
derHugo


내가하는 것처럼 문제가 무엇입니까?
derHugo

4
물론 문제가 있습니다. sudo사용자 이름 이 없는 스크립트 는 암호를 입력하지 않으면 암호를 묻습니다. 터미널에서 스크립트를 실행하지 않으면 암호 쿼리를 볼 수 없으며 작동하지 않습니다. sudo -u접근 방식은 이러한 문제가 없습니다.
디저트

답변:


9

아니요, heredoc은 항상 줄 바꿈으로 끝납니다. 그러나 여전히 마지막 줄 바꿈을 제거 할 수 있습니다 (예 : Perl).

cat << 'EOF' | perl -pe 'chomp if eof'
First line
Second line
EOF
  • -p입력을 한 줄씩 읽고에 지정된 코드를 실행 -e하고 (수정 가능) 줄을 인쇄합니다.
  • chomp 는 마지막 줄 바꿈이 있으면 제거합니다. eof 는 파일 끝에서 true를 반환합니다.

1
(이 경우 폐쇄 된 파이프) 파일의 끝 발생은 (어떤 히어 닥와 herestring 추가 자동입니다) 마지막 줄에서 줄 바꿈 문자를 씹는 것 당 경우 @Yaron
세르지 Kolodyazhnyy

7

Heredoc이 줄 끝 기호없이 echo -ne과 유사하게 동작하는 방법이 있습니까?

짧은 대답은 heredoc과 herestrings는 그와 같은 방식으로 구축되었으므로 no-here-doc과 herestring은 항상 새로운 줄 바꿈을 추가 할 것이며 옵션을 사용할 수있는 옵션이나 기본 방법이 없습니다 (아마도 bash 릴리스에있을 것입니까?).

그러나 bash 전용 방법을 통해 접근하는 한 가지 방법은 heredoc이 표준 while IFS= read -r방법을 통해 제공하는 것을 읽는 것이지만 마지막 줄 printf바꿈없이 지연을 추가하고 마지막 줄을 인쇄 하는 것입니다. bash 전용으로 할 수있는 작업은 다음과 같습니다.

#!/usr/bin/env bash

while true
do
    IFS= read -r line || { printf "%s" "$delayed";break;}
    if [ -n "$delayed" ]; 
    then
        printf "%s\n" "$delayed"
    fi
    delayed=$line
done <<EOF
one
two
EOF

여기에 보이는 것은 IFS= read -r line접근 방식 이있는 일반적인 while 루프 이지만 각 줄은 변수에 저장되어 지연됩니다 (따라서 첫 번째 줄 인쇄를 건너 뛰고 저장하고 두 번째 줄을 읽었을 때만 인쇄를 시작합니다). 그렇게하면 마지막 줄을 캡처 할 수 있으며 다음 반복 read에서 종료 상태 1을 반환하면 개행을 통해 마지막 줄을 통해 인쇄 printf합니다. 장황? 예. 그러나 작동합니다.

$ ./strip_heredoc_newline.sh                                      
one
two$ 

알아 차리는 $더 줄 바꿈이 없기 때문에 프롬프트 문자는 앞으로 추진되고. 그것에서 작동해야하므로 보너스로,이 솔루션은 휴대용 및 POSIX 틱입니다 kshdash뿐만 아니라.

$ dash ./strip_heredoc_newline.sh                                 
one
two$

6

다른 접근법을 시도하는 것이 좋습니다. 여러 개의 echo 문과 heredoc에서 생성 된 스크립트를 함께 정리하는 대신. 하나의 heredoc을 사용하는 것이 좋습니다.

heredoc 내에서 변수 확장 및 명령 대체를 사용할 수 있습니다. 이 예에서와 같이 :

#!/bin/bash
cat <<EOF
$USER $(uname)
EOF

나는 이것이 종종 출력을 한 조각 씩 만드는 것보다 훨씬 더 읽기 쉬운 최종 결과로 이어진다는 것을 알았습니다.

또한 #!스크립트 시작 부분 에서 줄을 잊어 버린 것 같습니다 . 그만큼#! 줄은 올바른 형식의 스크립트에서 필수입니다. #!줄 없이 스크립트를 실행하려고하면 형식이 잘못된 스크립트를 해결하는 셸에서 호출하는 경우에만 작동하며,이 경우에도 의도하지 않은 다른 셸에서 해석 될 수 있습니다.


잊어 버렸지 #!만 내 코드 블록은 2000 줄 스크립트 중 하나입니다.) 지금 당신의 제안이 while 루프에서 한 줄의 코드를 생성하는 문제를 어떻게 해결하는지 알 수 없습니다 ...
derHugo

루프가 필요한 라인 부분에 대한 @derHugo 명령 대체는이를위한 한 가지 방법입니다. 다른 방법은 heredoc 전에 변수에서 해당 부분을 구성하는 것입니다. 두 가지 중 가장 읽기 쉬운 것은 루프에 필요한 코드 길이와 해당 행 앞에 몇 줄의 heredoc이 있는지에 달려 있습니다.
kasperd

스크립트에서 이전에 정의 된 쉘 함수를 호출하는 @derHugo 명령 대체는 한 줄을 생성하기 위해 상당한 양의 코드가 필요한 경우 더 읽기 쉬운 세 번째 방법입니다.
kasperd

@derHugo : (1) 필요한 모든 명령을 변수에 넣는 루프를 가질 수 있습니다. (2) $( ...command...)heredoc 내에서 사용 하여 heredoc의 해당 지점에 해당 명령의 출력을 인라인으로 삽입 할 수 있습니다 . (3) Bash에는 배열 변수가있어 인라인으로 확장하고 대체를 사용하여 필요한 경우 시작 / 끝에 항목을 추가 할 수 있습니다. 이 두 가지를 함께 사용하면 kasperd의 제안이 훨씬 강력 해지고 스크립트가 훨씬 더 읽기 쉽습니다.
psmears

나는 일종의 템플릿 행동 (wysiwyg) 때문에 heredocs를 사용하고 있습니다. 다른 곳에서 전체 템플릿을 생성하고 내 의견으로 heredoc에 전달하는 것보다 실제로 읽기 / 유지 관리하기가 쉽지 않습니다.
derHugo

2

Heredocs는 항상 줄 바꿈 문자로 끝나지만 간단히 제거 할 수 있습니다. 내가 아는 가장 쉬운 방법은 head프로그램입니다.

head -c -1 <<EOF | sudo tee file > /dev/null
my
heredoc
content
EOF

쿨 나는 그것이 -c또한 부정적인 가치를 가지고 있다는 것을 몰랐다 ! pearl솔루션
derHugo

1

원하는 방식으로 개행을 제거 할 수 tr있습니다. 배관 이 가장 간단합니다. 이것은 물론 모든 줄 바꿈을 제거합니다.

$ tr -d '\n' <<EOF 
if ((
EOF

그러나 if 문을 작성하는 데 필요하지 않으면 산술 표현식 (( .. ))에 줄 바꿈이 포함되어 있어도 제대로 작동합니다.

그래서 당신은 할 수 있습니다

cat <<EOF 
if ((
EOF
for name in x y; do 
    cat << EOF
    ( \$${name}_E != 0 && \$${name}_E != 1 ) ||
EOF
done
cat <<EOF
    0 )) ; then 
    echo do something
fi
EOF

생산

if ((
    ( $x_E != 0 && $x_E != 1 ) ||
    ( $y_E != 0 && $y_E != 1 ) ||
    0 )) ; then 
    echo do something
fi

그러나 루프로 빌드하면 여전히 추악합니다. 은 || 0우리가 첫 번째 또는 마지막 줄 특별한 경우에 필요하지 않는 것이 물론 지금의가있다.


또한 | sudo tee ...모든 출력에 해당 정보가 있습니다. 리디렉션을 한 번만 열고 (프로세스 대체로) 나중에 인쇄 할 때이를 사용하여 제거 할 수 있다고 생각합니다.

exec 3> >(sudo tee outputfile &>/dev/null)
echo output to the pipe like this >&3
echo etc. >&3
exec 3>&-         # close it in the end

솔직히 말해서, 나는 여전히 외부 스크립트의 변수에서 변수 이름을 만드는 \$${name}_E것이 약간 추악하다고 생각하며 아마도 연관 배열 로 대체해야한다고 생각합니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.