echo * の実行結果について

  • フォーラムは新サイトへ移行しました。
  • このフォーラムではゲスト投稿が禁止されています
前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 .2 .3 .4 .5 .6 .7 | 投稿日時 2013-7-6 14:34
moduku  新米 居住地: 東京  投稿数: 4
「echoコマンドの引数に「*」を指定した場合、シェルは「*」を表示せずカレントディレクトリの内容を表示します。これは、シェルが「*」をメタキャラクタとして特別に認識するためです。」

102の問題解説にこんな記述があったのですが、意味が分かりません。
なぜ、文字列のワイルドカードに過ぎない「*」が、カレントディレクトリの一覧に化けるのでしょうか?
どなたか教えていただけると助かります。

なお、自分では以下のようなサイトを見たのですが、上記の疑問は解決せずです。
http://itpro.nikkeibp.co.jp/article/COLUMN/20090602/331173/
前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 | 投稿日時 2013-7-6 17:37
ktkyz  一人前   投稿数: 22
modukuさん

> なぜ、文字列のワイルドカードに過ぎない「*」が、カレントディレクトリの一覧に化けるのでしょうか?
メタキャラクタというのは、シェルによって文字列(ファイル又はディレクトリ)の一覧
(*の場合はカレントディレクトリのすべてのファイル・ディレクトリ)に展開されてからコマンドに渡されます。
どんな場合も同じように扱われます。扱いが変わる(化ける)ことはありません。

例えば、カレントディレクトリ(実機環境にて検証)に
[root@mimiken bk_test]# ls -l
合計 0
-rw-r--r--. 1 root root 0 7月 6 16:52 2013 AAAA
-rw-r--r--. 1 root root 0 7月 6 16:52 2013 BBBB
-rw-r--r--. 1 root root 0 7月 6 16:52 2013 CCCC
3つのファイルがあった場合を考えます。

「*」= AAAA BBBB CCCC
と展開されます。
展開された後に、コマンドに渡されます。

例えば、下に示す2つのlsコマンドは、
「ls AAAA BBBB CCCC」=「ls *」
は同じ扱いになります。

[root@mimiken bk_test]#
[root@mimiken bk_test]# echo *
AAAA BBBB CCCC
[root@mimiken bk_test]#
[root@mimiken bk_test]# ls AAAA BBBB CCCC
AAAA BBBB CCCC
[root@mimiken bk_test]# ls *
AAAA BBBB CCCC
[root@mimiken bk_test]#
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2013-7-6 18:02
moduku  新米 居住地: 東京  投稿数: 4
ktkyz さん、早速の返信ありがとうございます。
イマイチ理解できていないのは、書いていただいた以下の部分です。
どういった理屈で、0以上の文字列である「*」がAAAA BBBB CCCCというファイル名に展開されるんでしょうか?

>「*」= AAAA BBBB CCCC
>と展開されます。
>展開された後に、コマンドに渡されます。
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2013-7-6 18:11 | 最終変更
arashi1977  長老 居住地: 広島  投稿数: 1715
※スマホからだと表示が変になったので編集しなおしました
※さらに間違っていたので内容修正しました。

'*'ではなく、*と入力してるんですよね?

「echoコマンドに渡す引数として任意の文字列であるワイルドカードアスタリスク('*')」を指定したのか、シェルに「カレントディレクトリで選択可能な全て=ワイルドカード(*)」と渡したのかの違いです。

例えばですが
$ ls
a.txt b.txt c.txt
d.txt e.txt f.txt
1.log 2.log 3.log
な状況で
find . -name '*.txt'
→ find コマンドに 「*.txt」という名前のファイルを探すよう指示
→→ findコマンドが「*」を解釈して、検索結果として「a.txt, b.txt, c.txt, d.txt, e.txt, f.txt」を返す

find . -name *.txt
→ シェルが「*」を展開して
find . -name a.txt b.txt c.txt d.txt e.txt f.txt
というコマンドを実行しようとする
→→ find コマンドに 「a.txt, b.txt, c.txt, d.txt, e.txt, f.txt」という名前のファイルを探すよう指示
は明確に異なります。

その*が誰(シェル?実行対象コマンド?)に対して渡されるのか、がポイントですね
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2013-7-6 20:52 | 最終変更
ktkyz  一人前   投稿数: 22
modukuさん

>どういった理屈で、0以上の文字列である「*」がAAAA BBBB CCCCというファイル名に展開されるんでしょうか?
についてですが、メタキャラクタ(*)の意味は「カレントディレクトリにあるすべてのファイル名又はすべてのディレクトリ名の一覧で条件が0以上の文字列にマッチするものをスペース区切りしたもの」理屈を説明するため、あえて回りくどい表現に;
<言い換えればカレントディレクトリにあるすべてのファイル名やディレクトリ名の文字列をスペース区切したものに展開
ファイル名は少なくとも1文字以上のため、すべてのファイル名・ディレクトリ名を示します。

検証環境の例では、カレントディレクトリにファイル名「AAAA」と「BBBB」と「CCCC」の3つのファイルがある例です。3つのファイル名とも0以上の文字列条件にマッチする、言い換えればすべてのファイル名の間にスペースを入れて
「*」=「AAAA BBBB CCCC」と展開されます。

展開された後に、コマンドに渡されます。
例えば、「echo *」は「*」=「AAAA BBBB CCCC」と展開されechoコマンドに渡され
「echo *」= 「echo AAAA BBBB CCCC」 となります。

文字列をメタキャラクタを使用して「AA*」とした場合は、ファイル名「AAAA」にしかマッチしないため、
「A*」=「AAAA」と展開されます。
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2013-7-7 16:27
moduku  新米 居住地: 東京  投稿数: 4
ktkyzさん

度々詳説いただき、ありがとうございます。
echoは、渡された情報に*がある場合は、カレントディレクトリのファイル名と解釈して処理するって仕様なんですね。
ということで理解しました。
どうも、有難うございました。
>その*が誰(シェル?実行対象コマンド?)に対して渡されるのか、がポイントですね

101,102を先月合格したばかりなんですが、これから受験しようとしている後輩の質問に答えられず、挙げちゃいました。
また何かあれば宜しくお願いします。
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2013-7-7 19:14 | 最終変更
ktkyz  一人前   投稿数: 22
modukuさん

>echoは、渡された情報に*がある場合は、カレントディレクトリのファイル名と解釈して処理するって仕様なんですね。
はい、仕様と考えてよいと思います。
正確に言えば、カレントディレクトリ配下のすべてのファイル名とすべてのディレクトリ名の一覧となります。

因みに、その他のメタキャラクタ(「?」「.」など)理屈は同様です。
シェルにより、カレントディレクトリ配下のファイル名とディレクトリ名と比較して、条件にマッチしたファイル名・ディレクトリ名の一覧をスペース区切りに展開します。
後輩の方に説明するのも、丸暗記だけでなく理屈を解釈してからの方が今後につながるかと思います。理解できてよかったです。
前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 | 投稿日時 2013-7-8 8:42 | 最終変更
arashi1977  長老 居住地: 広島  投稿数: 1715
moduku さん、ktkyzさん

>echoは、渡された情報に*がある場合は、カレントディレクトリのファイル名と解釈して処理するって仕様

私の例でfindを挙げているように、echoに限らないというところだけは忘れないでくださいね

実機環境があれば以下のサンプルを試してみてください
(細かいファイル名はOS環境によって違いますが、挙動は同じです)
$ cd /boot
$ ls /boot
System.map@             grub/                   lost+found/
System.map-3.0.60-2vl6  initrd-3.0.60-2vl6.img  vmlinuz@
System.map-3.0.68-1vl6  initrd-3.0.68-1vl6.img  vmlinuz-3.0.60-2vl6
System.map.old@         initrd.img@             vmlinuz-3.0.68-1vl6
config-3.0.60-2vl6      initrd.old.img@         vmlinuz.old@
config-3.0.68-1vl6      kernel.h
$ set -x
$ echo '*'
+ echo '*'
*
$ echo *
+ echo System.map System.map-3.0.60-2vl6 System.map-3.0.68-1vl6 System.map.old c
onfig-3.0.60-2vl6 config-3.0.68-1vl6 grub initrd-3.0.60-2vl6.img initrd-3.0.68-1
vl6.img initrd.img initrd.old.img kernel.h lost+found vmlinuz vmlinuz-3.0.60-2vl
6 vmlinuz-3.0.68-1vl6 vmlinuz.old
System.map System.map-3.0.60-2vl6 System.map-3.0.68-1vl6 System.map.old config-3
.0.60-2vl6 config-3.0.68-1vl6 grub initrd-3.0.60-2vl6.img initrd-3.0.68-1vl6.img
 initrd.img initrd.old.img kernel.h lost+found vmlinuz vmlinuz-3.0.60-2vl6 vmlin
uz-3.0.68-1vl6 vmlinuz.old
※「+」で始まる行はデバッグ情報出力行です
set -x については以下をご覧ください。

シェルスクリプトのデバッグ - UNIX & Linux コマンド・シェルスクリプト リファレンス
http://shellscript.sunone.me/debug.html
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2013-7-9 0:17
moduku  新米 居住地: 東京  投稿数: 4
arashi1977 さん

感謝です。
クローズしたつもりの質問でしたが、新たな知識を得ることが出来ました。有難うございます。

>>ktkyzさん
度々、有難うございました。
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2013-7-15 5:41
takenin  新米   投稿数: 1
横から失礼致します。
> イマイチ理解できていないのは、書いていただいた以下の部分です。
> どういった理屈で、0以上の文字列である「*」がAAAA BBBB CCCCというファイル名に展開されるんでしょうか?

もしかしたら、grepなどに使う、正規表現とメタキャラクタが混同しているのではないでしょうか?
正規表現とメタキャラクタは別物で、私もこれを理解するのに苦労しました。

  >フォーラム検索へ


Copyright (c) 2020 Ping-t All rights reserved.