ディレクトリツリーを再帰的に操作して各ファイルで特定のコマンドを実行し、パス、ファイル名、拡張子、ファイルサイズ、およびその他の特定のテキストをbashの単一ファイルに出力するにはどうすればよいですか?
ディレクトリツリーを再帰的に操作して各ファイルで特定のコマンドを実行し、パス、ファイル名、拡張子、ファイルサイズ、およびその他の特定のテキストをbashの単一ファイルに出力するにはどうすればよいですか?
回答:
一方でfind
ソリューションはシンプルかつ強力で、私は基づいている、より複雑なソリューション、作成することを決めたこの興味深い機能私は数日前に見ました、。
1.と呼ばれる実行可能スクリプトファイルを作成します。このファイルは、シェルコマンドとしてアクセスできるようにwalk
配置され/usr/local/bin
ています。
sudo touch /usr/local/bin/walk
sudo chmod +x /usr/local/bin/walk
sudo nano /usr/local/bin/walk
nano
:Shift+ Insertペーストのため; Ctrl+ OおよびEnter保存用。Ctrl+ X終了。2.スクリプトの内容walk
は次のとおりです。
#!/bin/bash
# Colourise the output
RED='\033[0;31m' # Red
GRE='\033[0;32m' # Green
YEL='\033[1;33m' # Yellow
NCL='\033[0m' # No Color
file_specification() {
FILE_NAME="$(basename "${entry}")"
DIR="$(dirname "${entry}")"
NAME="${FILE_NAME%.*}"
EXT="${FILE_NAME##*.}"
SIZE="$(du -sh "${entry}" | cut -f1)"
printf "%*s${GRE}%s${NCL}\n" $((indent+4)) '' "${entry}"
printf "%*s\tFile name:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$FILE_NAME"
printf "%*s\tDirectory:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$DIR"
printf "%*s\tName only:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$NAME"
printf "%*s\tExtension:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$EXT"
printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$SIZE"
}
walk() {
local indent="${2:-0}"
printf "\n%*s${RED}%s${NCL}\n\n" "$indent" '' "$1"
# If the entry is a file do some operations
for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
# If the entry is a directory call walk() == create recursion
for entry in "$1"/*; do [[ -d "$entry" ]] && walk "$entry" $((indent+4)); done
}
# If the path is empty use the current, otherwise convert relative to absolute; Exec walk()
[[ -z "${1}" ]] && ABS_PATH="${PWD}" || cd "${1}" && ABS_PATH="${PWD}"
walk "${ABS_PATH}"
echo
3.説明:
このwalk()
関数の主なメカニズムは、Zannaの答えでかなりよく説明されています。したがって、新しい部分のみを説明します。
walk()
関数内にこのループを追加しました:
for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
つまり$entry
、ファイルであるそれぞれに対して関数が実行されますfile_specification()
。
この関数にfile_specification()
は2つの部分があります。最初の部分は、ファイルに関連するデータ(名前、パス、サイズなど)を取得します。2番目の部分は、適切にフォーマットされた形式でデータを出力します。データをフォーマットするには、コマンドを使用しprintf
ます。また、スクリプトを微調整する場合は、このコマンドについて読む必要があります。たとえば、この記事などです。
この関数file_specification()
は、各ファイルに対して実行する特定のコマンドを配置できる適切な場所です。次の形式を使用します。
コマンド「$ {entry}」
または、コマンドの出力を変数として保存してから、printf
この変数などを保存できます。
MY_VAR = "$(コマンド " $ {entry} ")" printf "%* s \ tファイルサイズ:\ t $ {YEL}%s $ {NCL} \ n" $((indent + 4)) '' "$ MY_VAR"
またはprintf
、コマンドの出力を直接:
printf "%* s \ tファイルサイズ:\ t $ {YEL}%s $ {NCL} \ n" $((indent + 4)) '' "$(command " $ {entry} ")"
と呼ばれる物sectionいのセクションColourise the output
は、printf
コマンド内で出力を色付けするために使用されるいくつかの変数を初期化します。詳細については、こちらをご覧ください。
スクリップの下部には、絶対パスと相対パスを扱う追加の条件が追加されます。
4.使用例:
walk
現在のディレクトリで実行するには:
walk # You shouldn't use any argument,
walk ./ # but you can use also this format
walk
子ディレクトリに対して実行するには:
walk <directory name>
walk ./<directory name>
walk <directory name>/<sub directory>
walk
他のディレクトリで実行するには:
walk /full/path/to/<directory name>
walk
出力に基づいてテキストファイルを作成するには:
walk > output.file
カラーコードなしで出力ファイルを作成するには(ソース):
walk | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" > output.file
5.使用法のデモンストレーション:
まだ誰も投稿していない理由については少し困惑していbash
ますが、globstar
オプションを有効にして**
glob を使用すると、実際には再帰的な機能があります。そのため、次のbash
ように再帰的なグロブスターを使用する(ほぼ)純粋なスクリプトを作成できます。
#!/usr/bin/env bash
shopt -s globstar
for i in ./**/*
do
if [ -f "$i" ];
then
printf "Path: %s\n" "${i%/*}" # shortest suffix removal
printf "Filename: %s\n" "${i##*/}" # longest prefix removal
printf "Extension: %s\n" "${i##*.}"
printf "Filesize: %s\n" "$(du -b "$i" | awk '{print $1}')"
# some other command can go here
printf "\n\n"
fi
done
ここでは、必要なファイル名の部分を取得するためにパラメーター拡張を使用し、ファイルサイズを取得し、du
出力をクリーニングする以外は外部コマンドに依存していないことに注意してくださいawk
。
そして、ディレクトリツリーを横断するときに、出力は次のようになります。
Path: ./glibc/glibc-2.23/benchtests
Filename: sprintf-source.c
Extension: c
Filesize: 326
スクリプトの使用に関する標準ルールが適用されます:で実行可能であることを確認chmod +x ./myscript.sh
し、現在のディレクトリから実行する./myscript.sh
か、に配置し~/bin
て実行しsource ~/.profile
ます。
"$(file "$i")"
(上記のスクリプトでprintfの2番目の部分として)返されるMIME情報が本当に必要ですか?
output the path, filename, extension, filesize
ので、答えは求められたものと一致します。:)
あなたがfind
仕事をするのに使うことができます
find /path/ -type f -exec ls -alh {} \;
これは、すべてのファイルをサイズでリストするだけの場合に役立ちます。
-exec
\;
ファイルを1つずつ解析するために使用される各ファイルに対してカスタムコマンドまたはスクリプトを実行できます
+;
。それらを連結する場合に使用できます(ファイル名を意味します)。
find
だけ。
find /path/ -type f -printf "path:%h fileName:%f size:%kKB Some Text\n" > to_single_file
または、代わりに以下を使用できます。
find -type f -not -name "to_single_file" -execdir sh -c '
printf "%s %s %s %s Some Text\n" "$PWD" "${1#./}" "${1##*.}" $(stat -c %s "$1")
' _ {} \; > to_single_file
find -printf
)。+1
ツリーの深さがわかっている場合、最も簡単な方法はワイルドカードを使用すること*
です。
シェルスクリプトまたは関数として、やりたいことをすべて書きます。
function thing() { ... }
その後、実行for i in *; do thing "$i"; done
、for i in */*; do thing "$i"; done
、...など
関数/スクリプト内で、いくつかの簡単なテストを使用して、操作したいファイルを選び出し、必要なことを実行できます。
$i
ます。
for i in */*
機能するか理解していないと思います。ここで、それをテストしますfor i in */*; do printf "|%s|\n" "$i"; done