GNU/Linux >> Linux の 問題 >  >> Linux

「ifs=Read -rLine」を理解していますか?

内部フィールドセパレータ変数に値を追加できることは明らかです。例:

$ IFS=blah
$ echo "$IFS"
blah
$ 

read -r lineも理解しています stdinからデータを保存します lineという名前の変数に :

$ read -r line <<< blah
$ echo "$line"
blah
$ 

しかし、コマンドはどのようにして変数値を割り当てることができますか?そして、最初に stdinからのデータを保存しますか 変数line 次に、 lineの値を指定します IFSへ ?

承認された回答:

POSIXシェルでは、 read 、オプションがないとは読み取れません 、単語を読み取ります 単語が$IFS である(おそらくバックスラッシュ-続きの)行から 区切り文字と円記号を使用して、区切り文字をエスケープする(または行を続ける)ことができます。

一般的な構文は次のとおりです。

read word1 word2... remaining_words

読む エスケープされていない改行文字(または入力の終わり)が見つかるまで一度に1バイトずつstdinを読み取り¹、複雑なルールに従ってそれを分割し、その分割の結果を $ word1に格納します。 、 $ word2 $initial_words

たとえば、次のような入力で:

  <tab> foo bar baz   blah   blah
whatever whatever

デフォルト値は$IFS read a b c 割り当てる:

  • $ a foo
  • $ b barbaz
  • $ c 何とか何でも

これで、引数を1つだけ渡した場合、それは read lineにはなりません。 。まだreadremaining_words 。バックスラッシュ処理は引き続き実行され、IFS空白文字²は最初と最後から削除されます。

-r オプションはバックスラッシュ処理を削除します。したがって、上記の -rを使用した同じコマンド 代わりに割り当てます

  • $ a foo
  • $ b バー
  • $ c bazblah blah

ここで、分割部分については、 $ IFSには2つのクラスの文字があることを理解することが重要です。 :IFS空白文字²(スペースとタブ(および改行を含みますが、ここでは-dを使用しない限り重要ではありません)。これもデフォルト値の $ IFS にあります。 )およびその他。これら2つのクラスのキャラクターの扱いは異なります。

IFS =:を使用 ( IFS空白文字ではない)、:foo ::bar ::のような入力 ""に分割されます 、 "foo" "" バー および"" (および追加の "" 一部の実装では、 read -a以外は問題ありません。 )。そのを置き換えると: スペースを使用すると、分割は fooのみに行われます。 およびbar 。つまり、先頭と末尾のものは無視され、それらのシーケンスは1つのように扱われます。 $ IFS で空白文字と非空白文字を組み合わせる場合は、追加の規則があります。 。一部の実装では、IFSの文字を2倍にすることで、特別な処理を追加/削除できます( IFS =:: またはIFS=''

したがって、ここで、先頭と末尾のエスケープされていない空白文字を削除したくない場合は、それらのIFS空白文字をIFSから削除する必要があります。

IFS以外の空白文字を使用している場合でも、入力行にそれらの文字が1つ(そして1つだけ)含まれていて、それが行の最後の文字である場合( IFS =:read -r word など) foo:のような入力で )POSIXシェル( zsh ではない) また、一部の pdksh バージョン)、その入力は1つの fooと見なされます これらのシェルでは、文字 $ IFS ターミネータと見なされます 、つまり word fooが含まれます 、 foo:ではありません 。

したがって、 readを使用して1行の入力を読み取る標準的な方法 組み込みは:

IFS= read -r line

(ほとんどの readに注意してください zsh を除いて、NUL文字はサポートされていないため、テキスト行に対してのみ機能する実装 。

関連:Linux – LinuxホストとWindowsゲスト間でファイルを共有しますか?

var =value cmdを使用する 構文により、 IFSが確認されます そのcmdの期間中のみ異なる設定になります コマンド。

履歴メモ

read ビルトインはBourneシェルによって導入され、すでに単語を読んでいました。 、行ではありません。最新のPOSIXシェルにはいくつかの重要な違いがあります。

Bourneシェルのread -rをサポートしていません オプション(Kornシェルによって導入された)。したがって、 sed's / \ / &&/ g'のようなもので入力を前処理する以外に、バックスラッシュ処理を無効にする方法はありません。 そこに。

Bourneシェルには、2つのクラスの文字の概念がありませんでした(これもkshによって導入されました)。 Bourneシェルでは、すべての文字がkshでのIFS空白文字と同じ扱いを受けます。つまり、 IFS =:read a b c foo ::barのような入力で barを割り当てます $ bへ 、空の文字列ではありません。

Bourneシェルでは、次のようになります:

var=value cmd

cmdの場合 組み込みです( read など) is)、 var valueに設定されたまま cmdの後 終わりました。これは、 $ IFSでは特に重要です Bourneシェルでは、 $ IFS 拡張だけでなく、すべてを分割するために使用されます。また、 $ IFSからスペース文字を削除した場合 Bourneシェルで、 "[email protected]" 動作しなくなりました。

Bourneシェルでは、複合コマンドをリダイレクトすると、サブシェルで実行されます(初期のバージョンでは、 read var などでも実行されます。 またはexec3<ファイル; var <&3を読む 動作しませんでした)、そのため、Bourneシェルで readを使用することはめったにありませんでした 端末でのユーザー入力以外の場合(その行継続処理が理にかなっている場合)

一部のユニス(HP / UXなど、 util-linux にも1つあります) )まだがあります 1行の入力を読み取るコマンド(Single UNIX Specificationバージョン2までは標準のUNIXコマンドでした)。

これは基本的にhead-n 1と同じです ただし、一度に1バイトずつ読み取って、複数行を読み取らないようにします。これらのシステムでは、次のことができます。

line=`line`

もちろん、これは新しいプロセスを生成し、コマンドを実行し、パイプを介してその出力を読み取ることを意味するため、kshの IFS =read -r lineよりもはるかに効率が低くなります。 、しかしそれでもはるかに直感的です。


Linux
  1. Ifsを理解していますか?

  2. 改行で終わらない可能性のある行指向のファイルを読みますか?

  3. エコーバックのないパスワードを取得するためのコマンドラインユーティリティ?

  1. Linuxデスクトップを理解していますか?

  2. Bashを使用してファイルの最後から2番目の行を読み取る方法は?

  3. Linux シリアルポートのリスナーとインタープリター?

  1. AnsibleのYAMLを理解する

  2. Busy Boxはファイルを1行ずつ読み取りますか?

  3. 各行を前後に出力するコマンド