쉘 명령 대체가 왜 마지막 줄 바꿈 문자를 고집합니까?


25

다음 예제와 같이 최근 질문 인 bash에서 마지막 줄 바꿈 문자는 어디로 갔습니까? , "왜"가 발생하는지 알고 싶습니다

  x="$(echo -ne "a\nb\n")" ; echo -n "$x" | xxd -p 
# Output is: 610a62 
# The trailing newline from the 'echo' command
#   has been "deleted" by Command Substitution

쉘 액션, 즉 Command Substitution이 대체하는 명령 출력에서 ​​일부 데이터를 실제로 삭제 해야하는 매우 중요한 이유 가 있다고 가정합니다 .
그러나이 것으로 생각되는 것처럼이 데이터를 둘러 볼 수는 없습니다. 이 것의 정반대 가정 .. 예를 할 수 있습니다. 명령의 출력을 스크립트 프로세스로 다시 전달하는 것 ... 한 문자를 붙잡는 것이 이상하게 보이지만 그 이유는 합리적이라고 생각합니다. 그 이유가 무엇인지 알고 싶습니다 .. .


답변:


22

쉘은 원래 완전한 프로그래밍 언어가 아니기 때문입니다.

\n일부 명령 출력에서 후행을 제거하는 것은 매우 어렵습니다 . 그러나 표시 목적으로 거의 모든 명령이로 출력을 종료 \n하므로 다른 명령에서 사용하려는 경우이를 제거하는 간단한 방법이 있어야합니다. 구성을 이용한 자동 제거가 $()선택된 솔루션이었습니다.

따라서이 질문을 답으로 받아 들일 수 있습니다.

\n다음 명령에서 후행 이 자동으로 수행되지 않은 경우 후행을 제거하는 간단한 방법을 찾을 수 있습니까 ?

> echo The current date is "$(date)", have a good day!

서식이 지정된 날짜에 나타날 수있는 이중 공백의 스매싱을 방지하려면 인용 부호가 필요합니다.


1
당신이 말하는 것이 사실이라면, 나는 절대적으로 기절 할 것입니다. A가있을 경우 shopt귀하의 설명 기본 동작을 변경하기 위해, 나는 다시 드리겠습니다 ... 나는 어려운 배쉬 / 리눅스 / 유닉스해서 "표준 출력을 캡처"등의 중요한 기능을 오염 것이라고 생각 찾을 수 date없습니다 '\ n'옵션의 유무에 관계없이 ... bash (또는 다른 쉘)에는 이것에 shopt대한 확실한 수정이 있습니다 ... 당신은 알고 있습니까? .. 그리고이 문제의 이유와 이유를 설명하는 참조 링크가 있습니까? ... date\ n 옵션 이없는 이유는 무엇입니까 ?
Peter.O

2
명령 대체는 1979 년 Unix의 "7th edition"에서 Bourne 쉘첫 번째 버전에 나타났습니다 . 이미 혁명이었으며 아무도 '\ n'을 유지하는 것에 관심이 없었던 것 같습니다. 예, 10 분 이내에 맨 페이지 를 읽을 수 있으며 그때까지 명령 대체에 대해 아무런 변화가없는 것 같습니다. 선호하는 $()대체 구문을 제외하고 .
Stéphane Gimenez

고마워. 나는 이것이 레거시 문제 일 수 있다고 생각했고, 내 명령 대체물을 좀 더주의 깊게 관찰하기 시작했다는 사실을 확실히 구체화하고있다. 오늘까지 나는 날개와기도에서 살아 남았어야했다. 내가 만난 "신비한 일들"중 일부는 지금 이해하기 시작했다. :) 당신의 "날짜"의 반대의 경우, 내 후행을 유지하고 싶습니다 \ n, 나는 다음과 같이 코딩해야합니다 :( { echo -n "The current date is "; var="$(date; echo -e x)"; var="${var%x}"; echo -n "$var"; echo ", have a good day!"; }.. 그러니 :)
Peter.O

PS 내 위의 코멘트를 다시 : 물론, 단지 date작동,하지만 난 그냥 사용 date의 예로서 어떤 명령 ..
Peter.O

날짜 에 관한 당신의 '질문'은 '왜'명령 서브 스터 션이 그 역할을 수행하는지에 대한 나의 이해에 대한 가장 강력한 주제였습니다. 그래서 이것은 내 질문에 대한 '최상의'답변이었습니다 ... ..
Peter.O

19

그것은 표준 의 일부입니다 :

쉘 은 서브 쉘 환경에서 명령 을 실행 하고 ( 쉘 실행 환경 참조 ) 명령 대체 ( 명령 텍스트와 "$ ()"또는 역 따옴표)를 명령의 표준 출력으로 대체하여 명령 대체를 확장해야합니다. 치환 종료시 하나 이상의 <개행>의 서열.

물론 표준은 이런 방식으로 작성 되었기 때문일 수도 있지만 표준이기 때문에 ksh표준으로 기록되어 있습니다. 마음에 들지 않으면 Perl이나 다른 줄 바꿈 문자를 사용하십시오.


좋은 요약 .. 감사합니다 .. 그리고 확실히 도움이되는 링크
Peter.O

4
그 표준은 Bourne 쉘이 그렇게 한 방식과 그 이후의 모든 쉘을 수행했기 때문입니다.
Gilles 'SO- 악마 그만해'

6

글쎄, 나에게 이해가된다. 줄 바꿈은 처음에는 일반 명령 출력에만 있기 때문에 명령이 새 줄에서 완료된 후에 프롬프트가 나타납니다. 개행은 대부분의 경우 원래 출력의 일부가 아니므로 화면을 정리해야합니다. 명령의 출력을 구문 분석 할 때 끝에 줄 바꿈이 일반적으로 번거 롭습니다. 왜 wc명령이 두 줄의 텍스트를 출력합니까? 아, 그렇지 않다면, 그 다음에 개행 문자가 출력됩니다. 파싱 wc할 때 2 줄의 출력이 있다는 사실에 대해 걱정하고 싶지 않습니다. 실제로 한 줄이 없습니다.


@EightBitTony : 내 질문은 어떤 식 으로든 터미널에 무언가를 표시하는 것과 관련이 없습니다. 매우 간단합니다. 표시 할 줄 바꿈이있는 경우 줄 바꿈이 표시됩니다. 여기서 중요한 점 \n은 원래 stdout스트림의 a가 명령 대체에 의해 제거된다는 것입니다. 즉. 데이터가 "인용 부호"로 묶여 있어도 내 원본 데이터 (매우 중요한 데이터)에 줄 바꿈 문자가 제거되었습니다. Word Splitting의 작동 방식과 이유를 합리적으로 이해하지만 Command Substitution이 개행후행 만 제거하는 이유를 전혀 모릅니다 .
Peter.O

1
당신이 말한 것이 내 견해를 바꾸지 않습니다. 종종 출력의 마지막 줄 바꿈은 데이터의 일부가 아닌 표시 목적으로 만 사용됩니다.
EightBitTony

나는 당신의 견해에 동의하고 모두 함께합니다 ... 그렇습니다. 출력 끝에 줄 바꿈 편의를위한 것입니다 ...하지만 내 문제는 그것과 아무런 관련이 없습니다 ... 나는 묻습니다 : 왜 명령 대체가 그것을 강제로 제거합니까? ? ...이 두 가지 다른 문제가 있습니다. 아마도 내 질문은 : 아마도 해결 방법이 있습니까? . 후행 더미 문자를 추가 하여이 문제를 코딩해야하기 때문에 짜증납니다! ... 그것은 ... 너무 너무 잘하지 .. :) 내가 필요하다면 나는 그것을 할 것이다, 그러나 이것은 내가 bash에 의해 좌절 봤는데 처음이다 (그리고 나는 충격의 상태에있어
베드로 .O

다른 답변에서 언급했듯이 표준의 일부입니다. 나를 위해, 나는 데이터를 후 처리 할 때 편리한 줄 바꿈이 아닌 데이터 만보 고 싶기 때문에 그렇게 생각한다고 생각합니다. 쉘 은 파이프에서 데이터를 처리하기를 기대 하고 개행은 데이터가 아니기 때문입니다. 더 이상 우리는 이것을 토론에 가져 가야합니다.
EightBitTony

고마워 .. 나는 지금 아이디어를 잘 얻었 어. 사령부 대체의 경우는 단순히 줄 바꿈을 유지하기보다는 후행 줄 바꿈을 포기하는 것에 의지하는 것 같다. "그러나 파일 이름에서 모든로-케이스 문자를 압도적으로 많이 사용하는 것이 다소 이상하고 불필요하다고 생각했지만, 그 전에는 실제로 꽤 편안한 시스템이라고 생각했습니다 .. 아마 언젠가는 명령 대체 행동의 운율과 이유를 더 깊이 본다.
Peter.O

1

나는 같은 문제가 발생하여 아래 예제를 발견했다. 인용이 상황에 도움이 된 것 같습니다.

http://tldp.org/LDP/abs/html/commandsub.html .

dir_listing=`ls -l`
echo $dir_listing     # unquoted

# Expecting a nicely ordered directory listing.

# However, what you get is:
# total 3 -rw-rw-r-- 1 bozo bozo 30 May 13 17:15 1.txt -rw-rw-r-- 1 bozo
# bozo 51 May 15 20:57 t2.sh -rwxr-xr-x 1 bozo bozo 217 Mar 5 21:13 wi.sh

# The newlines disappeared.


echo "$dir_listing"   # quoted
# -rw-rw-r--    1 bozo       30 May 13 17:15 1.txt
# -rw-rw-r--    1 bozo       51 May 15 20:57 t2.sh
# -rwxr-xr-x    1 bozo      217 Mar  5 21:13 wi.sh

2
여기에 무슨 일이 일어나고 있습니다. $strstring을 포함 하는 변수가 있다고 가정 해 봅시다 "a b c". 당신이 전달하는 경우 $strecho따옴표 (없이 echo $str), echo받을 것이다 a, b그리고 c세 개의 별도의 인수. 쉘은 인수 사이의 공백을 신경 쓰지 않습니다. echo그런 다음 인수를 공백으로 구분하여 각 인수를 인쇄하므로 얻을 수 "a b c"있습니다. 변수를 echo따옴표로 묶어 전달하면 ( echo "$str") 쉘 은 변수를 하나의 인수로보고이를 echo수신하므로 공백이 축소되지 않습니다. 개행에도 동일하게 적용됩니다.

1
원래 포스터의 문제점은 명령의 마지막 줄 바꿈이 사라진다는 것입니다. -n플래그를 전달하지 않으면 echo출력에 후행 줄 바꿈을 추가하므로 예제의 두 에코에 후행 줄 바꿈이 있습니다. 그러나 echo -n $dir_listing또는 을 시도 echo -n "$dir_listing"하면 뒤에 줄 바꿈 문자가 따옴표와 함께 또는 인용 부호없이 인쇄되지 않음 $dir_listing을 알 수 있습니다. 이는 명령 대체에 문제가 있음을 나타냅니다.

2
tldp는이다 심하게 쉘 스크립트에 대해 배울 수있는 오래된 곳. 대신 Wooledge Bash Wiki를 사용해보십시오. mywiki.wooledge.org/BashGuide
와일드 카드

-1

echo "hello "따옴표없이 왜 공간을 차지합니까? IFS 문자의 값은 셸에서 구분자로 표시되므로 끝 문자 (구체적으로 구분되지 않음)가 제거됩니다. 추천 대체는 하위 쉘에서 추천을 실행하는 것이 일반적이므로 동일한 논리를 따릅니다.


@Philomath : 모두 x="hello  "x="hello     "잃게됩니다 모든 을 통해 표시하는 경우 자신의 후행 공백을 echo $x... 그러나 단지 맨 마지막 명령 Substituton의 줄 바꿈이 손실됩니다.
Peter.O

이상하게도, 나는 내 배쉬 (xxd로 확인)에 어떤 차이도 보이지 않는다
Philomath

난 그냥 이것에 체크 ... 그것은 모든 후행 줄 바꿈을 제거 ... 그 인상을받을 때 IFS 실험하고 있었다, 그래서 그 하나를 취소하자 :) ..하지만 질문은 여전히 ​​남아 ... 그것은 근본적인 부분 단어 분할은 하나의 공간에 여러 공간을 응축하고, 완전히 선행 및 후행 공백 제거 .. 내가 할 수 그것을 이해하지만, 명령 치환과 함께, 그것은 왜 나는 확실히 이해하지 못하고 단지 로 (스트립 \ n 및 모든 공백 단어 분리), 그리고 왜 후행 만? .. 그리고 무엇보다도 : "명령 대체"는 부분적으로 만 대체됩니다. 왜?
Peter.O

4
IFS명령 대체가 끝날 때 줄 바꿈을 제거하는 것과는 아무런 관련이 없습니다.
Gilles 'SO- 악마 그만해'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.