Unixのawkを使用してフルパスをディレクトリとファイル名に分割する方法

このQ&Aのポイント
  • Unixのawkを使用してフルパスをディレクトリとファイル名に分割する方法について説明します。
  • awkコマンドを使用して、フルパスからディレクトリとファイル名を抽出する方法を詳しく解説します。
  • 具体的な例を挙げながら、awkを使ってフルパスをディレクトリとファイル名に分ける手順を説明します。
回答を見る
  • ベストアンサー

unixのawkについて

unixでawkを使ってフルパスからディレクトリとファイル名に分けようと しているのですが、上手くいきません。 例えば ①/aaa/bbb/ccc ②/111/222/333/hoge.txt ③/hoge/foo/bar/dk@0:1 を ①/aaa/bbb と ccc ②/111/222/333 と hoge.txt ③/hoge/foo/bar と dk@0:1 としたいのです。 echo "/111/222/333/hoge.txt" | gawk '{sub(/\/.*$/,"",$0); print}' としてみたのですが、 ディレクトリだけを取り出そうとしたのですが上手くいきません。 よろしくお願いします。 OSは、Solaris、Linuxになります。

質問者が選んだベストアンサー

  • ベストアンサー
  • asciiz
  • ベストアンサー率70% (6638/9405)
回答No.3

プログラミング以前の問題があるように思います。 >①/aaa/bbb/ccc この ccc は、見た目にファイル名であるかディレクトリであるかわかりません。 もし ccc がディスク上でディレクトリであれば、 「/aaa/bbb/ccc」と「(ヌル文字列)」に分けるのが正しいことになります。 その様な心配をしなくて良いのでしょうか。 ---- 指定された「フルパス」が必ずファイル名で終わっていると保証できるなら、ディレクトリ名は最後の「/」の手前まで、それ以降をファイル名、として取り出せば良いことになります。 >echo "/111/222/333/hoge.txt" | gawk '{sub(/\/.*$/,"",$0); print}' >としてみたのですが、 >ディレクトリだけを取り出そうとしたのですが上手くいきません。 これは、正規表現の性質として「"*"はできるだけ長くマッチする」ためです。 "/\/.*$/" を "/111/222/333/hoge.txt" に適用した場合、マッチするのは最初の「/」からお尻($)まで、すなわち文字列全体になってしまいます。 なので、「スラッシュ以外の任意長の文字列」とすれば、 echo "/111/222/333/hoge.txt" | gawk '{sub(/[^/]*$/,"",$0); print}' ファイル名の部分のみを削除できるでしょう。 まあこれだとディレクトリの末尾に / が残るので、マッチパターンを「スラッシュ + スラッシュ以外の任意長の文字列」にすれば echo "/111/222/333/hoge.txt" | gawk '{sub(/\/[^/]*$/,"",$0); print}' 「/111/222/333」が得られると思います。 そして逆にファイル名を得る方では、「最長マッチ」の性質を使い、 echo "/111/222/333/hoge.txt" | gawk '{sub(/^.*\//,"",$0); print}' これでファイル名だけになるんじゃないでしょうか。

abc999xyz
質問者

補足

ありがとうございます。 >もし ccc がディスク上でディレクトリであれば、 >「/aaa/bbb/ccc」と「(ヌル文字列)」に分けるのが正しいことになります。 >その様な心配をしなくて良いのでしょうか。 確かにあります。 ですが、拡張子なしだとファイルかディレクトリかわかりません。 cccがディレクトリかファイルかわからないので判断が必要ということですね。 どうなりますか。

その他の回答 (3)

  • asciiz
  • ベストアンサー率70% (6638/9405)
回答No.4

>cccがディレクトリかファイルかわからないので判断が必要ということですね。 >どうなりますか。 すみません、perlだと「ファイルテスト演算子」っていうのがあって、 if (-f $path) print "通常ファイル"; if (-d $path) print "ディレクトリ"; みたいな判別が出来たんですが、awkは主目的がテキスト処理言語であるせいか、そんなテストはできないようですね(汗 フォルダ関連の命令があれば、「chdir $path」をしてみてカレントディレクトリを移動できるか、みたいな判別法もできたかもしれませんが、そんなものも無いようです。 そうなると(awkでは)、「フルパス末尾はファイル名で終わっている」と仮定するしかない気がします…余計な申し出失礼しました。

abc999xyz
質問者

お礼

ありがとうございます。 疑問や指摘は大変参考になります。

  • agehage
  • ベストアンサー率22% (2552/11348)
回答No.2

awkじゃなきゃダメ? xargsでよければ以下のようにご希望の状況になるかと echo aaa/bbb/ccc | xargs -n1 basename → ccc echo aaa/bbb/ccc | xargs -n1 dirname → aaa/bbb echo /111/222/333/hoge.txt | xargs -n1 basename → hoge.txt echo /111/222/333/hoge.txt | xargs -n1 dirname → /111/222/333 echo /hoge/foo/bar/dk@0:1 | xargs -n1 basename → dk@0:1 echo /hoge/foo/bar/dk@0:1 | xargs -n1 dirname → /hoge/foo/bar

abc999xyz
質問者

お礼

ありがとうございます。 例として echo /111/222/~ | awk とかきましたが、 処理結果をawkに渡しているのでawkとなります。

  • _kappe_
  • ベストアンサー率68% (1522/2216)
回答No.1

awkでやらなければいけない理由はありますか? なければ、dirnameとbasenameで足りると思います。 $ dirname /hoge/foo/bar/dk@0:1 /hoge/foo/bar $ basename /hoge/foo/bar/dk@0:1 dk@0:1

abc999xyz
質問者

お礼

ありがとうございます。 例として echo /111/222/~ | awk とかきましたが、 処理結果をawkに渡しているのでawkとなります。

関連するQ&A

  • awk と gawk の書き方の違い

    PCでAWKコマンドを使いたくてgawkを使ってみたのですが、 やっぱりawkのような書き方では上手く実行できないみたいです。 gawkのバージョンは v3.1.6です。 コマンド (awk) awk -F, '{printf("copy aaa\%s bbb\%sn",$0,$0)}' list.txt 単純にDOSのバッチをファイルから作りたいだけなのですが・・・gawkではどのように書けば良いのか教えてください。お願いします。 仕事でUNIXを使っていたのですがPCに移行するという話がでていて、今までのunixコマンドをPCで動くようにソースを書き直して行かなくてはならないのにパスを『/』から『\』にしただけでは全く動きませんでした。やっぱりUNIXのawkでは出来てPCのgawkでは出来ないこともあるのでしょうか?それとも書き方の問題でしょうか??

  • awkの正規表現について

    ディレクトリ名とファイル名の一覧ファイルがあり、その中から特定ディレクトリの1階層下のディレクトリ名とファイル名を取得したいのですが、うまく抽出できません。 ディレクトリ名とファイル名の一覧ファイル(dir.txt)は /foo/ /foo/bar/ /foo/bar/a.txt /foo/bar/sub/ /foo/bar/sub/x.txt /foo/var/ /foo/var/b.txt /usr/ /usr/bar/ で「/foo/」指定すると /foo/ /foo/bar/ /foo/var/ を抽出し 「/foo/var/」を指定すると /foo/var/ /foo/var/b.txt を抽出したいです。 この場合、awk '$1 ~ /^\/foo\/bar\// {print}' dir.txtとすると /foo/bar/ /foo/bar/a.txt /foo/bar/sub/ /foo/bar/sub/x.txt が抽出されてしまいます。 どのような書き方をすれば1階層下のディレクトリとファイルのみを 抽出できるのでしょうか?

  • Unix初心者による初心者シェルプログラミングです。

    Unix初心者による初心者シェルプログラミングです。 以下のようなコマンドを羅列しただけの スクリプトが300行(実質100行ぐらい)が漸くできるようになりました。 これだけで、おばかさんな私は進化してます。が・・・ 対象となる、hoge.txtは、同ディレクトリ内に別名で、200ファイル有ります。 このスクリプトがその別名、200ファイルへと対象になります。 と云う事はファイル名分の200ファイル分スクリプトを編集して用意しなくては いけなくなる。 となると・・・ 別の事をしないといけませんよね。 どうやら、同ディレクトリ内にある、全ての .txt ファイルに対してこの スクリプトを実行させるには・・・ (よくわかりませんが・・・) FILE=`/home/foo/*.txt` みたいな・・・(全然違うと思っていますが、イメージで) /home/foo/ 内の .txt ファイルを一ファイルずつ読み込んで、実行させる方法が あると思うのですが・・・ 全てを教えて貰うつもりはありません。 学習していきます。 でも、疲れてきました。 がしかし、やらなくちゃいけません。 ヒント下さい。 お願いします! > cat hogehoge.sh #!/usr/bin/sh DAY=`/usr/xpg4/bin/date '+%Y/%m/%d%a'` HUMAN=`/usr/ucb/whoami` TIME=`/usr/xpg4/bin/date '+%H:%M:%S'` echo echo "$DAY : $HUMAN : PID $$" echo echo "$0" echo echo "$TIME Let's start!" echo echo "ls -l /home/foo/hoge.txt" ls -l /home/foo/hoge.txt echo echo "cat -n /home/foo/hoge.txt | head -15" cat -n /home/foo/hoge.txt | head -15 echo echo "sed -f /home/foo/script.sed /home/foo/hoge.txt > /home/foo/new-hoge.txt" sed -f /home/foo/script.sed /home/foo/hoge.txt > /home/foo/new-hoge.txt echo echo "ls -l /home/foo/new-hoge.txt" ls -l /home/foo/new-hoge.txt echo echo "cat -n /home/foo/new-hoge.txt | head -18" cat -n /home/foo/new-hoge.txt | head -18 echo echo "sed -e '1d' -e '14d' /home/foo/new-hoge.txt > /home/foo/renewal-hoge.txt" sed -e '1d' -e '14d' /home/foo/new-hoge.txt > /home/foo/renewal-hoge.txt echo echo "ls -l /home/foo/renewal-hoge.txt" ls -l /home/foo/renewal-hoge.txt echo echo "diff /home/foo/new-hoge.txt /home/foo/renewal-hoge.txt" diff /home/foo/new-hoge.txt /home/foo/renewal-hoge.txt echo echo "sed -e '13d' -e 's/^iranai/hitsuyou/' /home/foo/renewal-hoge.txt > /home/foo/new-hoge.txt" sed -e '13d' -e 's/^iranai/hitsuyou/' /home/foo/renewal-hoge.txt > /home/foo/new-hoge.txt echo echo "ls -l /home/foo/new-hoge.txt" ls -l /home/foo/new-hoge.txt echo ・ ・ ・ ・ ・ ・ ・ ・ 300

  • awkのセパレータ指定について

    awkのセパレータ指定について教えてください。 以下のようなファイルがありそれを'||'区切りで出力したいです。 下記のような指定をしてみたのですが、 うまくいきませんでした。 cat text | awk -F '||' '{print $1}' [test.txt] aaa||bbb||ccc [期待する結果] print $1 → aaa print $2 → bbb print $3 → ccc どなたか教えてください。 よろしくお願いします。

  • 2つの配列を比較し、一致しないのを得たいのですが

    連想配列 $foo = array( "aaa" => "111", "bbb" => "222", "ccc" => "333" ); と 一般配列 $bar = array( 0 => "aaa", 1 => "bbb" ); がある場合に、$iを数字として、 $fooのkey部と$bar[$i]の値が一致したら(つまり、例えばaaa)、 $fooの中のその部分は除去するような事がやりたいのですがどのようにすればいいのでしょうか? 色々試してみましたが、自分には全く出来ませんでした。 除去ではなく、新しい配列に $hoge = array( "ccc" => "333" ) のような形で入れ込むのでもいいのですが、とくかく$hogeのような配列を手に入れたいと考えております。 アドバイス頂けないでしょうか? 宜しくお願い致します。

    • ベストアンサー
    • PHP
  • 今、awkを使ったシェルスクリプトを作っています。

    今、awkを使ったシェルスクリプトを作っています。 aaa bbb ccc ddd ee ff gggg hhh といったファイルから、 bbb,ccc ff,gggg を取り出したいと思っています。 そこで、以下のコマンドをwhileでまわして、$iを増加させることにより、 ファイルを一行ずつ読み取り、目的の列を取り出したく思っています。 A=`cat sample.txt|awk 'NR == $i {print NR, $2;}'` B=`cat sample.txt|awk 'NR == $i {print NR, $3;}'` ところが、awkコマンドの中の$iがシングルクォーテーションでくくられているので、 変数展開されなくて困っています。 何かよい方法があればご教授いただけますでしょうか?

  • awkでスラッシュがある動的変数の抽出について

    2つのテキストファイルがあり、directorylist.txtから1行取り出し、filelist.txtから対応するファイルを抽出したいのですが directorylist.txtに「/」があるため 「正規表現が終端されていません」というエラーがでます。 どのようにしたら、抽出できるのでしょうか? while read LINE; do awk ' $2 = '"$LINE"' { print $1 }' filelist.txt done < directorylist.txt ●filelist.txt [File名] [Directory名] a.txt /home/hoge/ del.txt /home/hoge/ b.txt /home/foo/ ●directorylist.txt [Directory名] / /home /home/hoge

  • awkによるあるプログラムその2

    立て続けに申し訳ないですが、 次のプログラムを実行すると、 gawk: ./test.awk:19: fatal: function name `foo' previously defined というエラーになってしまいます。 なぜでしょうか? #!/usr/bin/gawk -f #test.awk: BEGIN{ a="OK"; b="OK"; c="OK"; print foo(1,2); print a,b,c; print bar("AWK is", "convenient"); print a,b,c; print "4!==" recursive(4); } function foo(a,b, c){ c=a+b; return c; } function foo(a,b, c){ c=a b; return c; } function recursive(a){ if(a<=1)return 1; else return a*recursive(a-1); }

  • unixのコマンドでSQLのようにJOINする

    unixのコマンドでSQLのJOIN(直積)と同じことをする方法はありますか? やりたいのは同じ結合キーが複数行ある場合です。 入力ファイル1(結合キーは1列目) 1,AAA 2,BBB 2,CCC 3,DDD 入力ファイル2(結合キーは1列目) 1,PPP 2,QQQ 2,RRR 出力結果 1,AAA,PPP 2,BBB,QQQ 2,BBB,RRR 2,CCC,QQQ 2,CCC,RRR 結合キー「2」は入力ファイル1にも入力ファイル2にも2行づつ存在するので SQLのJOINと同じように組み合わせのパターン全部を出力し、 結合キー「3」は入力ファイル2には存在しないので出力したくありません。 もし簡単なコマンドがなければawkやperlを使うしかないでしょうか・・・。 環境はHitachi系のunixだったと思います(うろ覚え) ちなみにこういう質問はこのカテゴリ(Linux系OS)で合ってますでしょうか。プログラミングと迷ったのですが・・・。

  • 置換コマンド

    freeBSD5.3を使用している初心者です。 あるディレクトリ以下の全ファイルに対し、一度に内容の文字を置換したいのですがうまくいきません。 例えば /hoge/aaa.txt /hoge/bbb.txt /hoge/ccc.txt と、/hoge以下に3ファイルがあり、このファイルにAAAという文字列があるなら、AAAをBBBにしたいと思っています。 sed s/AAA/BBB/g /hoge/* とすると、置換後の中身が表示はされますが、それに置きかわったファイルは/hoge/以下に保存されていません。(もとのAAAのまま) できたら、/hoge 以下の置換されたファイルを/hoge2以下に同じ名前で保存させたいと思っています。 どなたか是非アドバイスお願いいたします。