![awk スクリプトでのパイプ処理](https://rvso.com/image/23956/awk%20%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%81%A7%E3%81%AE%E3%83%91%E3%82%A4%E3%83%97%E5%87%A6%E7%90%86.png)
の出力を解析するために をls
使用するラッパーを書こうとしています。現在、プログラムを 2 つのファイルに分割しています。の唯一の目的は、 の出力を にパイプすることです。次のようになります。awk
ls -lhF
my_ls.sh
my_ls.awk
my_ls.sh
ls -lhF
my_ls.awk
#!/bin/bash
ls -lhF "$@" | my_ls.awk
ls -lhF
awk スクリプト自体から出力を読み取る方法があるかどうか疑問に思っていました。
編集:私の主な目的は、現在のディレクトリの内容をきれいなツリー形式で表示するスクリプトを書くことです。 のドラフト版は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
ものを印刷しようとするが、実際にはそうではないとみなされるもの (デフォルトの解析による) です。例: ls
awk
-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
、 の場合のように、予期しない単純ではない出力を送信する可能性があることに注意してください。link
そのため、通常は、find
の出力を使用して、解析のニーズに合わせてカスタマイズする方が安全です。
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 フラグが使用されている場合、dircolors のように色がサポートされます。引数がない場合、tree は現在のディレクトリ内のファイルをリストします。ディレクトリ引数が指定されている場合、tree は指定されたディレクトリ内で見つかったすべてのファイルおよび/またはディレクトリを順番にリストします。見つかったすべてのファイル/ディレクトリのリストが完了すると、tree はリストされたファイルおよび/またはディレクトリの合計数を返します。
デフォルトでは、シンボリック リンクが検出されると、シンボリック リンクが参照するパスがリンク名の後に次の形式で印刷されます。
名前 -> 実パス
'-l' オプションが指定され、シンボリック リンクが実際のディレクトリを参照している場合、tree は実際のディレクトリであるかのようにシンボリック リンクのパスをたどります。