bashの変数にコマンド出力を保存すると、「正規表現でエスケープされていない開かれた中括弧が廃止されました」が発生します。

bashの変数にコマンド出力を保存すると、「正規表現でエスケープされていない開かれた中括弧が廃止されました」が発生します。

正誤表:

同様の質問が提起されましたが、数日間検索した後も、この特定のシナリオに対する回答はないようです。

問題の説明:

次のbashスクリプトの2行目はエラーを引き起こします。

#!/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"コマンドは、現在のユーザーの権限が上昇しているかどうかによって異なる結果を返します。

したがって、スクリプトの移植性のためには、現在のセッションユーザー名を確実に取得する必要があります。これは、同じユーザー名を永遠に維持しない可能性があり、誰でもログインしても、私のスクリプトが機能し続けるためです。

これは、バックアップされるユーザーファイルが多数のファイルを含む巨大なディレクトリ構造を持っているためです。定期的に、ルート所有権と権限を持つファイルがユーザーのバックアップスタックに表示されます。

これはさまざまな理由で発生する可能性があります。場合によっては、ユーザーがシステムディレクトリ構造内のお気に入りの壁紙やテーマをバックアップしたことがあり、時にはユーザーがプロジェクトと必要な特定のディレクトリまたはファイルをコンパイルしたためです。特定の方法で実行するようにrootの所有権と権限に設定されているが、時には不明な他の奇妙な理由が原因である可能性があります。

私はrsyncがこの問題を解決できることを知っていますが、まずBashスクリプトの問題で「エスケープされていない開かれたかっこ」を解決する方法を理解したいと思います。

rsyncを直接見てみることもできますが、数日間試してみましたが、このbashスクリプトには、オンライン検索やマニュアルを読んでも簡単に発見または説明できる解決策がないようです。

[更新01]:

元の投稿には一部の情報がないため、ここに追加します。関連するシステム仕様は次のとおりです。

  • オペレーティングシステム:ジュブント 16.04 x86_64
  • 大きな打撃:GNU bash、バージョン 4.3.46(1)-リリース(x86_64-pc-linux-gnu)

私が使用するコマンドのソースと根拠は次のとおりです。

次のスレッドの3番目の答えは次のとおりです。

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が提供する選択されたソリューションは、ある記事で私のスクリプトに関連するすべての問題を明確に説明しました。出力で括弧の問題が発生したため、スクリプトの2行目を誤って想定しました。明確に言えば、警告を生成するのは3番目の行です(理由と方法はChazelasの投稿を参照)。これがおそらく誰もがprintの代わりにprintfを推奨する理由でしょう。提案を理解するには、スクリプトの3行目を指すだけです。

提案どおりに機能しなかったこと:

 sessionuser=$(logname)

結果のエラーメッセージ:

 logname: no login name

…ですから、このアドバイスは見えるほど確実ではないかもしれません。

ユーザー権限が上昇した場合(これはスクリプトの実行時に時々発生します):

 id -un 

出力されます

 root

現在のセッションのユーザー名の代わりに。これは、実行前にスクリプトがroot権限で終了することを確認する簡単な問題である可能性があります。これは問題を解決しますが、これはこのスレッドの範囲外です。

推奨事項に従って実行された、または実行可能な操作:

私のスクリプトがPOSIX環境で実行されていることを確認し、どういうわけかroot権限を取り消す方法を見つけた後、実際に「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エラーが発生したのは、2行目ではなく3行目()です。

print銀とkshでは、テキストを出力するための組み込みコマンドです。代わりにまたはを使用する必要があります。zshbashbashprintfecho

また、bash(反対zshですが類似ksh)では、変数を引用する必要があります。

だからzsh

print $sessionuser

(しかしあなたが意図したのは疑わしいです:

print -r -- $sessionuser

目的が標準出力に書き込む場合、この変数の内容(後に改行文字が続く)は次の場所にありますbash

printf '%s\n' "$sessionuser"

zsh(/にも適用されますksh)。

一部のシステムには、ファイルシステムにプリンタprintに何かを送信する実行可能なコマンドがあります。ここでは実際にそれを呼び出します。ほとんど使用されていないという証拠は、perl正規表現のperl不適切な使用について警告するという事実を説明するために、アップグレード後の実装(Debianの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)問題を解決することです。lognameidid/usr/xpg4/bin/binps/bin/id

呼び出すユーザーを知りたい場合は、環境変数を渡すことがsudoできます。$SUDO_USER次のsudoユーザー名です。本物実行中のプロセスのユーザーID sudosudo後で、その実際のユーザー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コマンドはbashsudoそしてどちらの方法も見つからないシステムが多いです。

答え2

注文はどこから来ましたか/usr/bin/print? IlはUbuntuのシンボリックリンクですrun-mailcap

代わりにechoorを使用しないのはなぜですか?printfprint

関連情報