awkスクリプトのパイプ

awkスクリプトのパイプ

lsこれで、プログラムを2つのファイルに分割しました。awkの唯一の目的は。次のようになります。ls -lhFmy_ls.shmy_ls.awkmy_ls.shls -lhFmy_ls.awk

#!/bin/bash
ls -lhF "$@" | my_ls.awk

ls -lhFawkスクリプト自体を介して出力を読み取る方法があるかどうか疑問に思います。

編集する:私の主な目的は、現在のディレクトリの内容を素晴らしいツリーの形で表示するスクリプトを書くことです。ドラフトバージョンはmy_ls.awk次のとおりです。

#!/usr/bin/awk -f

( NF >= 9 ) {
    print "|-- [" $5 "] " $9
}

これこれが私がこれまでに達成したことです。

答え1

出力を解析してはならないという別の提案を追加するので、lsこれは悪い例です。しかし、より一般的な質問にawkスクリプトをパラメータとしてawk

#!/bin/bash
ls -lhF "$@" | awk '
    ( NF >= 9 ) {
        print "|-- [" $5 "] " $9
    }'

awkスクリプトに'(二重引用符)文字を含める必要がある場合は、引用符で囲む必要があります。'\''(閉じる一重引用符、リテラル一重引用符、開く一重引用符)を使用してください。

引用を避けるには、次のものを使用できます。ここのドキュメント代わりに。ただし、標準入力を使用してawkとスクリプトの両方に入力を提供できないため、これは厄介です。追加のファイル記述子を使用する必要があります(参照:追加のファイル記述子はいつ使用されますか? ファイル記述子とシェルスクリプト)。

#!/bin/bash
ls -lhF "$@" | awk -f /dev/fd/3 3<<'EOF'
( NF >= 9 ) {
    print "|-- [" $5 "] " $9
}
EOF

awkでは、getline関数とパイプ構成を使用して他のコマンドの入力を読み取ることができます。これはawkの基本的な目的ではありませんが、うまく機能させることができます。エラーが発生しやすい基本シェルのファイル名引数を引用する必要があります。処理中のテキストが期待されるソース(標準入力またはコマンドラインで名前付きファイル)から出ていないため、最終的にブロック内のすべてのコードが生成されますBEGIN

#!/usr/bin/awk -f
BEGIN {
    command = "ls -lhF"
    for (i = 1; i <= ARGC; i++) {
        arg = ARGV[i];
        gsub("'", "'\\''", arg);
        command = command " '" arg "'";
    }
    ARGC = 0; for (i in ARGV) delete ARGV[i];
    while ((command | getline) > 0) {
        if (NF >= 9) { print "|-- [" $5 "] " $9 }
    }
}

簡単に言えば、シェルがうまくいく操作(コマンドを一緒にリンクするなど)にはシェルを使用し、うまくいくタスク(テキスト処理など)にはawkを使用します。

答え2

何をしたいのかわかりませんが、発生する可能性のある問題の1つは、最後のフィールドと見なされますが、基本的な解析ではそうではないものをawk印刷することです。例えば。 lsawk

-rw-r--r-- | 433k | filename-with-no-spaces      
-rw-r--r-- |   1k | link containing  spaces -> /home/user/filename-with-no-spaces

どういうわけか最後のフィールドを分離する必要がありますls。以下で取り上げたアプローチは、すべての前のフィールドと区切り文字の長さを見つけることです。残りはファイル名フィールド(リンク先などの他の情報を含む)です。 

以下のスクリプトは、可変幅の最大幅を決定します。サイズフィールド(出力形式に必要)たとえば、この幅を取得する方法はさまざまです。(1)awk各出力ラインを処理するには、ls メインループで後続の処理のために各ラインを配列に追加しますEND{ }。または(2) 出力をls一時ファイルに書き込み、awkファイルを処理します。下記の方法を使用してください。(2)

lsの場合のように、出力は予期しないマイナーな出力を希望の方法で送信できるため、通常は解析要件に合わせて出力を使用してカスタマイズする方が安全ですlinkfind

f=7               # the number of (multi-space) delimiters before the start of the filename  
myls="$(mktemp)"  # a temp file to hold  output from `ls`
w=$(ls --color=always -lFHk ~/ |tee "$myls" |awk '{print $5}' |wc -L) # max width of size field
h=k               # size unit
awk --re-interval -v"f=$f" -v"w=$w" -v"h=$h" '
  NF >= f {
    regex = "^([^ ]+ +){"f"}" 
    match( $0, regex )  # find start of name field
    printf( "%s | %"w"s%s | %s\n", $1, $5, h, substr( $0, RLENGTH ))
  }' "$myls"
rm "$myls"

答え3

treeホイールの再発明を避け、代わりにディレクトリのファイル/フォルダとサブディレクトリのファイル/フォルダを表示することをお勧めします。

tree(1) - Linux のマニュアルページ

名前

ツリー - ディレクトリの内容をツリー形式で一覧表示します。

要約

tree[-adfghilnopqrstuvxACDFNS] [-L レベル[-R]] [-H baseHREF] [-T タイトル] [-o ファイル名] [--nolinks] [-P モード] [-I モード] [--inodes] [ --device] [--noreport] [--dirsfirst] [--version] [--help] [--filelimit #] [ディレクトリ...]

説明する

Treeは、深くインデントされたファイルのリストを生成する再帰的なディレクトリリストプログラムです。 LS_COLORS 環境変数が設定され、出力が tty で構成され、-C フラグが使用される場合、カラー ala dircolors がサポートされます。引数がない場合、treeは現在のディレクトリのファイルを一覧表示します。ディレクトリ引数が与えられると、ツリーは与えられたディレクトリに見つかったすべてのファイルおよび/またはディレクトリを順番にリストします。見つかったすべてのファイル/ディレクトリの一覧が完了すると、ツリーは一覧表示されたファイルとディレクトリの総数を返します。

デフォルトでは、シンボリックリンクが見つかると、シンボリックリンクで参照されるパスが次の形式でリンク名の後に印刷されます。

名前 - >実際のパス

「-l」オプションが指定されており、シンボリックリンクが実際のディレクトリを参照している場合、ツリーは実際のディレクトリであるかのようにシンボリックリンクのパスに従います。

関連情報