bash의 변수에 명령 출력을 저장하면 "정규 표현식에서 이스케이프되지 않은 여는 중괄호가 더 이상 사용되지 않음"이 발생합니다.

bash의 변수에 명령 출력을 저장하면 "정규 표현식에서 이스케이프되지 않은 여는 중괄호가 더 이상 사용되지 않음"이 발생합니다.

정오표:

비슷한 질문이 제기되었지만 며칠 동안 검색한 후에도 이 특정 시나리오에 대한 답변이 없는 것 같습니다.

문제 설명:

다음 bash 스크립트의 두 번째 줄은 오류를 유발합니다.

#!/bin/bash
sessionuser=$( ps -o user= -p $$ | awk '{print $1}' )
print $sessionuser

오류 메시지는 다음과 같습니다.

Unescaped left brace in regex is deprecated, passed through in regex; marked by <-- HERE in m/%{ <-- HERE (.*?)}/ at /usr/bin/print line 528.

내가 시도한 것들:

  1. $() 명령 출력 캡처 방법 내부와 외부에서 생각할 수 있는 작은따옴표, 후행 작은따옴표, 큰따옴표 및 공백의 모든 조합을 시도했습니다.
  2. $( exec ... )를 사용해 보았습니다. 여기서 ...는 여기서 시도한 명령입니다.
  3. 나는 bash에 대해 읽고 이 포럼과 다른 많은 포럼을 검색했지만 이 오류 메시지가 발생하는 이유나 해결 방법을 설명하는 내용이 없습니다.

오류 메시지에 제공된 조언을 따르는 경우:

sessionuser=$( ps -o user= -p 1000 | awk '\{print $1}' )

이전 오류 메시지와 결합되어 다음 오류 메시지가 표시됩니다.

awk: cmd. line:1: \{print $1}
awk: cmd. line:1: ^ backslash not last character on line
Unescaped left brace in regex is deprecated, passed through in regex; marked by <-- HERE in m/%{ <-- HERE (.*?)}/ at /usr/bin/print line 528.

이 메시지는 /usr/bin/print의 528행을 나타냅니다. 다음 줄은 다음과 같습니다.

$comm =~ s!%{(.*?)}!$_="'$ENV{$1}'";s/\`//g;s/\'\'//g;$_!ge;

내 bash 스크립트의 합리성:

$USER 문자열은 덮어쓸 수 있으므로 반드시 신뢰할 수 있는 것은 아닙니다. "whoami" 명령은 현재 사용자의 권한이 상승했는지 여부에 따라 다른 결과를 반환합니다.

따라서 스크립트 이식성을 위해서는 현재 세션 사용자 이름을 안정적으로 가져오는 것이 필요합니다. 이는 동일한 사용자 이름을 영원히 유지하지 않을 수도 있고 누구로 로그인하든 내 스크립트가 계속 작동하기를 원하기 때문입니다.

이 모든 일은 백업되는 사용자 파일이 많은 파일을 포함하는 거대한 디렉터리 구조를 갖고 있기 때문에 발생합니다. 주기적으로 루트 소유권과 권한이 있는 파일이 사용자의 백업 스택에 나타납니다.

이는 여러 가지 이유로 발생할 수 있습니다. 때로는 사용자가 시스템 디렉터리 구조에서 좋아하는 배경화면이나 테마를 백업했기 때문일 수도 있고 때로는 사용자가 프로젝트와 필요한 특정 디렉터리 또는 파일을 컴파일했기 때문일 수도 있습니다. 특정 방식으로 실행되도록 루트 소유권 및 권한으로 설정되지만 때로는 알 수 없는 다른 이상한 이유 때문일 수도 있습니다.

나는 rsync가 이 문제를 해결할 수 있다는 것을 알고 있지만 먼저 Bash 스크립트 문제에서 "이스케이프되지 않은 여는 중괄호"를 해결하는 방법을 이해하고 싶습니다.

rsync를 직접 살펴볼 수도 있지만 며칠 동안 시도해 본 결과 이 ​​bash 스크립트에는 온라인 검색이나 매뉴얼을 읽어도 쉽게 발견하거나 설명할 수 있는 해결책이 없는 것 같습니다.

[업데이트 01]:

원래 게시물에는 일부 정보가 누락되어 여기에 추가합니다. 관련 시스템 사양은 다음과 같습니다.

  • 운영 체제:주분투 16.04 x86_64
  • 큰 타격:GNU bash, 버전 4.3.46(1)-릴리스(x86_64-pc-linux-gnu)

내가 사용하는 명령의 소스와 근거는 다음과 같습니다.

다음 스레드의 세 번째 답변은 다음과 같습니다.

https://stackoverflow.com/questions/19306771/get-current-users-username-in-bash

인쇄 및 인쇄

내가 복사한 소스가 "print" 구문을 사용하기 때문에 "printf" 대신 "print"를 사용하여 이 질문을 게시하고 있습니다. "printf"를 사용한 후 동일한 오류 메시지가 표시되지만 출력에 오류 메시지가 추가됩니다.

Unescaped left brace in regex is deprecated, passed through in regex; marked by <-- HERE in m/%{ <-- HERE (.*?)}/ at /usr/bin/print line 528.
Error: no such file "sessions_username_here"

여기서 "sessions_username_here"는 실제 세션 사용자 이름을 대체하여 사용 가능하거나 사용될 수 있는 모든 사용자 이름에 대한 논의를 일반화합니다.

[최종 업데이트]

Stéphane Chazelas가 제공한 선택된 솔루션은 한 기사에서 내 스크립트와 관련된 모든 문제를 명확하게 설명했습니다. 출력에서 괄호에 대한 문제가 발생했기 때문에 스크립트의 두 번째 줄을 잘못 가정했습니다. 명확하게 말하면 경고를 발생시키는 것은 세 번째 줄입니다(이유와 방법은 Chazelas의 게시물 참조). 이것이 아마도 모든 사람들이 print 대신 printf를 권장하는 이유일 것입니다. 제안 사항을 이해하려면 스크립트의 세 번째 줄만 가리키면 됩니다.

제안된 대로 작동하지 않은 사항:

 sessionuser=$(logname)

결과 오류 메시지:

 logname: no login name

...그래서 이 조언은 보이는 것만큼 확실하지 않을 수도 있습니다.

사용자 권한이 상승된 경우(이는 스크립트를 실행할 때 가끔 발생함):

 id -un 

출력됩니다

 root

현재 세션의 사용자 이름 대신. 이는 실행하기 전에 스크립트가 루트 권한으로 종료되는지 확인하는 간단한 문제일 수 있으며, 그러면 문제가 해결되지만 이는 이 스레드의 범위를 벗어납니다.

권장 사항에 따라 수행되었거나 수행할 수 있는 작업:

내 스크립트가 POSIX 환경에서 실행되고 있는지 확인하고 어떻게든 루트 권한을 취소하는 방법을 알아낸 후 실제로 "id -un"을 사용하여 현재 세션 사용자 이름을 가져올 수 있지만 이러한 확인 및 취소는 그 범위를 벗어납니다. 문제.

현재 POSIX 유효성 검사, 권한 테스트 및 다운그레이드는 "아니요"이며 스크립트는 오류 없이 원래 의도된 작업을 수행합니다. 이제 스크립트는 다음과 같습니다.

 #!/bin/bash
 sessionuser=$( ps -o user= -p $$ | awk '{printf $1}' )
 printf '%s\n' "$sessionuser"

참고: 상승된 권한으로 위 스크립트를 실행하는 경우 권한 에스컬레이션 명령을 실행하더라도 현재 세션 사용자 이름 대신 "root"가 계속 출력됩니다.

 sudo ps -o user= -p $$ | awk '{printf $1}'

"root" 대신 현재 세션 사용자 이름을 출력하므로 이 스레드의 범위에 응답했더라도 이 스크립트를 사용하면 원점으로 돌아갑니다.

xtrmz, icarus, 특히 이 문제에 대한 나의 오해를 잡아준 Stéphane Chazelas에게 다시 한 번 감사드립니다. 나는 여기 있는 모든 사람들에게 깊은 인상을 받았습니다. 도와주셔서 감사합니다! :)

답변1

print $sessionuser오류가 발생한 것은 두 번째 줄이 아니라 세 번째 줄( )입니다 .

print은 및 ksh에서는 텍스트를 출력하기 위한 내장 명령입니다 . 대신 또는 를 사용해야 합니다 .zshbashbashprintfecho

또한 bash(반대 zsh이지만 유사 ksh)에서는 변수를 인용해야 합니다.

그래서 zsh:

print $sessionuser

(하지만 당신이 의도한 것은 의심스럽습니다:

print -r -- $sessionuser

목적이 표준 출력에 쓰는 것이라면 이 변수의 내용(뒤에 개행 문자가 옴)은 다음 위치에 있습니다 bash.

printf '%s\n' "$sessionuser"

zsh( / 에도 적용됩니다 ksh).

일부 시스템에는 파일 시스템에 print프린터로 무언가를 보내는 실행 가능한 명령이 있는데, 여기서는 실제로 이를 호출합니다. 거의 사용되지 않는다는 증거는 perl정규 표현식의 perl부적절한 사용에 대해 경고한다는 사실을 설명하기 위해 업그레이드 후 구현(데비안의 mime 지원 패키지의 일부인 내 구현과 동일)이 업데이트되지 않았다는 것입니다 {. 알아 차렸다.

{는 정규식 연산자입니다(예: x{min,max}). 여기서는 정규식 구문 분석 오류로 인해 실패하는 대신 이를 허용하고 문자 그대로 처리하는 %{(.*?)}경우 가 (.*?)아닙니다 . 이전에는 이에 대해 침묵했지만 이제는 코드(여기)에 문제가 있을 수 있다는 경고를 보고합니다. 연산자를 사용하려고 했지만 코드에 문제가 발생한 것입니다. 아니면 그렇지 않은 경우 해당 .min,maxperl{print{{

그런데 간단히 다음을 사용할 수 있습니다.

sessionuser=$(logname)

시작 스크립트가 속한 로그인 세션의 사용자 이름을 가져옵니다. getlogin()표준 POSIX 기능을 사용합니다 . GNU 시스템에서 이 쿼리는 일반적으로 tty 로그인 세션에만 적용됩니다(유사한 터미널 에뮬레이터가 등록된 tty를 사용하는 utmp경우 ).loginutmp

또는:

sessionuser=$(id -un)

id실행 중인 프로세스의 유효 사용자 ID (스크립트를 실행한 동일한 사용자) 와 동일한 uid를 가진 사용자의 이름을 가져옵니다 .

ps -p "$$"실행될 쉘 호출이 id확장 호출과 동일 $$하고 그 외에는 zsh(// 특수 변수에 할당하여 EUID) 쉘이 다른 명령을 실행하지 않고는 uid를 변경할 수 없다는 점에서 접근 방식과 동일합니다 . 물론, 모든 명령에서, UIDUSERNAMEid물론아니요setuid로 설정)

둘 다 표준(POSIX) 명령입니다(Solaris에서는 다른 많은 명령과 마찬가지로 에서 고대 명령이 아니라 에서 명령을 호출하고 있는지 확인하기 위해 POSIX 환경에 있어야 합니다 id. 유일한 귀하가 링크한 답변에 사용하는 목적은 Solaris의 제한 사항을 해결하는 것입니다.lognameidid/usr/xpg4/bin/binps/bin/id

호출하는 사용자를 알고 싶다면 환경 변수를 sudo전달할 수 있습니다 . $SUDO_USER다음 sudo사용자 이름 입니다.진짜실행 중인 프로세스의 사용자 ID입니다 sudo. sudo나중에 해당 실제 사용자 ID를 대상 사용자의 ID( root기본값)로 변경하여 이 $SUDO_USER변수가 그것이 무엇인지 알 수 있는 유일한 방법이 되도록 합니다.

이 작업을 수행할 때 다음 사항에 유의하세요.

sudo ps -fp "$$"

이는 쉘을 실행하는 프로세스의 $$pid가 아닌 호출 쉘의 pid로 확장되므로 여기에는 제공되지 않습니다.sudosudopsroot

sudo sh -c 'ps -fp "$$"'

shroot현재 계속 실행 중인 명령(다음으로 실행)을 실행한 프로세스를 제공 sh하거나 마지막 명령에 대해 추가 프로세스를 포크하지 않은 호출 ps에 대해 제공합니다.sh

동일한 작업을 수행 ps -p "$$"하고 sudo that-script.

어떤 경우에도 POSIX 명령은 bash. sudo그리고 어느 쪽의 방법도 찾지 못하는 시스템이 많습니다.

답변2

주문은 어디서 왔나요 /usr/bin/print? Il은 우분투의 심볼릭 링크일 수 있습니다 run-mailcap.

대신 echoor 를 사용하지 않는 이유는 무엇 입니까 ?printfprint

관련 정보