스크립트에서 문자열의 쉘 독립적 이스케이프

스크립트에서 문자열의 쉘 독립적 이스케이프

나는 이것 때문에 (다시) 어려움을 겪고 있습니다.

# only in bash
NORM=$'\033[0m'
NORM=$'\e[0m'

# only in dash
NORM='\033[0m'

# only in bash and busybox
NORM=$(echo -en '\033[0m')

echo목표는 출력 사용 뿐만 아니라 CLI 도구 등에 대한 파이프용으로 문자열에 특수 문자를 포함하는 것입니다 .

위의 특정 사용 사례에서는 를 사용하는 것이 $(tput ...)아마도 최선의 접근 방식일 것입니다. 그러나 외부 도구에 대한 요구 사항은 최소화하면서 호환성은 최대화하는 일반적인 이스케이프 솔루션을 요구합니다.

보통 [ -z "$BASH_VERSION" ]"but"와 같은 조건문을 사용하여 도움을 줍니다.

  1. 비지박스를 감지하는 쉬운 방법을 찾지 못했습니다.
  2. 5번째 줄의 일반 변수 할당(if/else/fi 사용)은 다소 과도해 보입니다.
  3. 나는 간단한 해결책을 선호한다

답변1

당신이 원하는 것은 입니다 "$(printf ...)". Stephen은 훌륭한 폭로 글을 썼습니다.printf그리고echo, 단순한 답변이라기보다는 기사에 가깝기 때문에 여기서는 전체 내용을 반복하지 않겠습니다. 현안과 관련된 기조연설은 다음과 같습니다.

  1. ~에 따르면POSIX 기능그리고 휴대성이 매우 좋고
  2. 이는 일반적으로 쉘 내장이며, 이 경우 외부 호출이나 종속성이 없습니다.

echo또한 익숙해 지고 복잡할 것이라고 echo생각했기 때문에 전환하는 데 오랜 시간(예, 단 몇 주)이 걸렸다고 덧붙일 것입니다 . printf(이 모든 플래그는 무엇에 관한 것일까 요?) 실제로는 매우 간단하며 %끝에 개행 문자가 있는 고정 텍스트 이외의 다른 printf작업에는 더 이상 신경 쓰지 않습니다 .echo


Printf가 쉬워졌습니다

수많은 옵션이 있습니다 printf. 특정 소수점 이하 자릿수까지 숫자를 인쇄할 수 있습니다. 각각 지정된 고정 너비(또는 최소 또는 최대 너비)를 가진 여러 필드를 인쇄할 수 있습니다. 문자 시퀀스를 포함하는 쉘 문자열 변수를 만들 \t거나 \n이러한 문자 시퀀스를 인쇄용 탭 및 줄 바꿈으로 해석할 수 있습니다.

이 모든 일을 할 수 있고, 필요할 때 찾아볼 수 있도록 가능하다는 것을 알아야 하지만,대부분의 경우 알아야 할 사항은 다음과 같습니다.

printf첫 번째 인수로 "format"이라는 문자열을 사용합니다. 형식 문자열은 추가 매개변수를 처리하는 방법(예: 형식 지정 방법)을 지정할 수 있습니다. 다른 매개변수(형식 매개변수*에서 전혀 인용되지 않은 경우)는 다음과 같습니다.무시당하다.

영숫자 문자(및 기타 문자)를 형식 매개변수에 포함시켜 그대로 인쇄할 수 있으므로바라보다like는 printf동일한 작업을 수행 echo -n하지만 알 수 없는 이유로 첫 번째 인수를 제외한 모든 인수를 무시합니다. 그러나 실제로는 그렇지 않습니다.

예를 들어, printf some test text이 예에서 try some는 실제로 다음과 같이 처리됩니다 .체재printf, 그리고 여기에는 특별한 내용이 포함되어 있지 않고 나머지 인수로 무엇을 해야 할지 알려주지 않기 때문에 해당 인수는 무시되고 인쇄되는 것은 모두 입니다 some.

%printf후속 매개변수에 포함된 데이터 유형을 지정 하려면 형식 문자열( 의 첫 번째 매개변수)과 특정 문자가 와야 합니다 .%s"문자열"을 의미하며 가장 많이 사용하게 될 것입니다.

\n또는 \t각각 형식에 따라 줄바꿈과 탭으로 변환합니다.

이것이 실제로 효율적으로 사용하는 데 필요한 전부입니다 printf. 매우 간단한 몇 가지 예시를 보려면 다음 코드 블록을 참조하세요.

$ var1="First"
$ var2="Second"
$ var3="Third"
$ printf "$var1" "$var2" "$var3"       # WRONG
First$                                 # Only the first arg is printed, without a trailing newline
$
$ printf '%s\n' "$var1"                # %s means that the next arg will be formatted as a literal string with any special characters printed exactly as-is.
First
$
$ printf '%s' "$var1" "$var2" "$var3"  # When more args are included than the format calls for, the format string is reused.  This example is equivalent to using '%s%s%s' as the format.
FirstSecondThird$                      # All three args were printed; no trailing newline.
$
$ printf '%s\t%s\t%s\n' "$var1" "$var2" "$var3"
First   Second  Third                  # Tab separation with trailing newline.  This format is very explicit about what to do with three arguments.  Now see what happens if four are used:
$ var4="Fourth"
$ printf '%s\t%s\t%s\n' "$var1" "$var2" "$var3" "$var4"
First   Second  Third             # The specified format is reused after the three expected args,
Fourth                            # so this line has two trailing tabs.
$
$ printf '%s\n' "$var1" "$var2" "$var3"  # This format reuse can be used to advantage in printing a list, for example.
First
Second
Third
$
$ printf '%s\t' "$var1" "$var2" "$var3" ; printf '\n'  # Here is a dual command that could have args added without changing the format string...
First   Second  Third   
$ printf '%s\t' "$var1" "$var2" "$var3" "$var4" ; printf '\n'
First   Second  Third   Fourth              # ...as you can see here.
$                                           # It does print a trailing tab before the newline, however.

* 물론 단일 인수 형식 지정자 시퀀스(예:)를 포함하는 경우 %s전체 형식 문자열은 제공된 모든 인수를 처리하는 데 필요한 만큼 재사용됩니다. 예시를 참조하세요.

답변2

printf임의의 8진수 등을 인쇄하는 데 적합하지만 단지 입력만 하고 싶을 때ESC- 그럼 그냥 입력하시면 됩니다. 식생활 탈출이 걱정된다면 이렇게 해보세요CTRL+V첫 번째.

그래서...

NORM='^[[0m'

...위 순서를 입력한 후 화면에 표시되는 내용을 볼 수 있습니다. tty는 인쇄할 수 없는 문자의 출력을 이런 방식으로 인용하지만 쉘은 텍스트를 읽습니다.ESC문자^[이스케이프 시퀀스의 위치입니다.

이 기능은 구성 가능하기는 하지만 터미널 에뮬레이터 프로그램이나 셸 또는 다른 것과는 독립적입니다. 시스템 커널은 stty유틸리티 구성에 따라 입력을 관리합니다. 기본 설정 - BSD, Linux 또는(내가 아는 한)거의 모든 UNIX 계열 시스템 - 일반적으로 다음 대부분을 포함합니다.

stty --help 2>&1 | sed -e '/Special/,$!d;/./!q'

Special characters:
 * discard CHAR  CHAR will toggle discarding of output
   eof CHAR      CHAR will send an end of file (terminate the input)
   eol CHAR      CHAR will end the line
 * eol2 CHAR     alternate CHAR for ending the line
   erase CHAR    CHAR will erase the last character typed
   intr CHAR     CHAR will send an interrupt signal
   kill CHAR     CHAR will erase the current line
 * lnext CHAR    CHAR will enter the next character quoted
   quit CHAR     CHAR will send a quit signal
 * rprnt CHAR    CHAR will redraw the current line
   start CHAR    CHAR will restart the output after stopping it
   stop CHAR     CHAR will stop the output
   susp CHAR     CHAR will send a terminal stop signal
 * swtch CHAR    CHAR will switch to a different shell layer
 * werase CHAR   CHAR will erase the last word typed

이것다음문자는 일반적으로 구성되는 문자입니다.CTRL+V. 그것은 유용할 수 있습니다 - 당신은 할 수 있습니다CTRL+V그 다음에CTRL+J예를 들어, 개행 문자는 쉘이 읽을 기회를 갖기 전에 입력 버퍼에 삽입됩니다. 한 번 시도해 보십시오 $PS2. 그렇지 않으면 볼 수 있는 쉘의 프롬프트가 표시되지 않는다는 것을 알 수 있습니다. 납치된 포탄의 경우TAB키를 사용하는 경우 일반적으로 명령줄에 접두사를 붙여 키를 그대로 입력할 수 있습니다.CTRL+V. 텍스트를 입력할 수 있습니다.CTRL+D EOF문자와 텍스트CTRL+C 정수수치(사용하지 않는 경우 zsh)같은 방법으로.

그런데, 이러한 문자의 대부분은 쉘에 특별하지 않으며 문자 그대로 입력할 때 인용할 필요조차 없습니다.(물론 개행도 가능하지만).

stty -a귀하의 터미널이 어떻게 구성되어 있는지 명확하게 파악 하십시오 . 아마도 내 터미널 및 다른 모든 터미널과 거의 동일하게 구성되어 있을 것입니다.

실제로 입력하면ESC쉘 스크립트를 편집하면 파일에 그대로 유지됩니다. 리터럴 문자는 스크립트가 호출될 때마다 배치되는 위치이며 적절한 의미를 부여하기 위해 확장이나 다른 해석이 필요하지 않습니다.

관련 정보