グループコマンドとサブシェル
bash コマンドをグループ化できるようになります。 これは XNUMX つの方法のいずれかで実行できます。 または グループコマンド または サブシェル。 それぞれの構文の例を次に示します。
グループコマンド:
{コマンド1; コマンド2; [コマンド3; ...] }
サブシェル:
(コマンド1; コマンド2; [コマンド3;...])
XNUMX つの形式は、グループ コマンドがコマンドを中かっこで囲み、サブシェルがかっこを使用するという点で異なります。 方法の都合上、注意が必要です bash グループコマンドを実装する場合、中括弧はスペースでコマンドから区切る必要があり、最後のコマンドは右中括弧の前にセミコロンまたは改行で終了する必要があります。
では、グループ コマンドとサブシェルは何に役立つのでしょうか? これらには重要な違いがありますが (これについてはすぐに説明します)、どちらもリダイレクトを管理するために使用されます。 複数のコマンドでリダイレクトを実行するスクリプト セグメントを考えてみましょう。
ls -l > 出力.txt
echo "foo.txt のリスト" >>output.txt cat foo.txt >>output.txt
ls -l > 出力.txt
echo "foo.txt のリスト" >>output.txt cat foo.txt >>output.txt
これは非常に簡単です。 XNUMX つのコマンドとその出力は という名前のファイルにリダイレクトされます。 output.txt。 グループ コマンドを使用すると、これを次のようにコーディングできます。
{ ls -l; echo "foo.txt のリスト"; 猫ふー.txt; } > 出力.txt
{ ls -l; echo "foo.txt のリスト"; 猫ふー.txt; } > 出力.txt
サブシェルの使用も同様です。
(ls -l; echo "foo.txt のリスト"; cat foo.txt) > Output.txt
(ls -l; echo "foo.txt のリスト"; cat foo.txt) > Output.txt
この手法を使用すると、入力の手間が省けますが、グループ コマンドまたはサブシェルが真価を発揮するのはパイプラインです。 コマンドのパイプラインを構築する場合、多くの場合、複数のコマンドの結果を XNUMX つのストリームに結合すると便利です。 グループ コマンドとサブシェルを使用すると、これが簡単になります。
{ ls -l; echo "foo.txt のリスト"; 猫ふー.txt; } | lpr
{ ls -l; echo "foo.txt のリスト"; 猫ふー.txt; } | lpr
ここでは、XNUMX つのコマンドの出力を結合し、それらを次の入力にパイプしています。 lpr 印刷されたレポートを作成します。
次のスクリプトでは、グループ コマンドを使用し、連想配列と組み合わせて使用できるいくつかのプログラミング手法を見ていきます。 このスクリプトは、 配列-2は、ディレクトリの名前を指定すると、ディレクトリ内のファイルのリストと、ファイルの所有者およびグループ所有者の名前を出力します。 リストの最後に、スクリプトは各所有者とグループに属するファイル数の集計を出力します。 ここでは、スクリプトにディレクトリを指定した場合の結果 (簡潔にするために要約) を示します。
/usr/bin:
[me @ linuxbox〜] $ 配列-2 /usr/bin | ||
/usr/bin/2to3-2.6 | ルート | ルート |
/usr/bin/2to3 | ルート | ルート |
/usr/bin/a2p | ルート | ルート |
/usr/bin/ブラウザ | ルート | ルート |
/usr/bin/aconnect | ルート | ルート |
/usr/bin/acpi_fakekey | ルート | ルート |
/usr/bin/acpi_listen | ルート | ルート |
/usr/bin/add-apt-リポジトリ | ルート | ルート |
. | ||
. | ||
. | ||
/usr/bin/zipgrep | ルート | ルート |
/usr/bin/zipinfo | ルート | ルート |
/usr/bin/zipnote | ルート | ルート |
/usr/bin/zip | ルート | ルート |
/usr/bin/zipsplit /usr/bin/zjsdecode /usr/bin/zsoelim | ルート ルート ルート | ルート ルート ルート | |
ファイル所有者: デーモン: 1 | ファイル | ||
ルート : 1394 | ファイル |
ファイルグループ所有者: crontab : 1 ファイル daemon : 1 ファイル lpadmin : 1 ファイル mail : 4 ファイル mlocate : 1 ファイル root : 1380 ファイル shadow : 2 ファイルssh : 1 ファイル
tty : 2 ファイル
utmp : 2 ファイル
#!/ bin / bashに
#!/ bin / bashに
# array-2: 配列を使用してファイル所有者を集計します
宣言 -A files file_group file_owner グループの所有者 if [[ ! -d "$1" ]]; それから
echo "使用法: array-2 dir" >&2 exit 1
fi
for i in "$1"/*; do owner=$(stat -c %U "$i") group=$(stat -c %G "$i") files["$i"]="$i" file_owner["$i"]=$所有者ファイル グループ["$i"]=$group ((++owners[$owner])) ((++groups[$group]))
行われ
# 収集したファイルを一覧表示する
{ for i in "${files[@]}"; do printf "%-40s %-10s %-10s\n"
"$i" ${file_owner["$i"]} ${file_group["$i"]} 完了 } | 選別
# array-2: 配列を使用してファイル所有者を集計します
宣言 -A files file_group file_owner グループの所有者 if [[ ! -d "$1" ]]; それから
echo "使用法: array-2 dir" >&2 exit 1
fi
for i in "$1"/*; do owner=$(stat -c %U "$i") group=$(stat -c %G "$i") files["$i"]="$i" file_owner["$i"]=$所有者ファイル グループ["$i"]=$group ((++owners[$owner])) ((++groups[$group]))
行われ
# 収集したファイルを一覧表示する
{ for i in "${files[@]}"; do printf "%-40s %-10s %-10s\n"
"$i" ${file_owner["$i"]} ${file_group["$i"]} 完了 } | 選別
以下はスクリプトのリスト (行番号付き) です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
27
28
29
30
31
32
33
34
35
36
37
38
39
40
echo
echo
# 所有者のリストを表示する
echo "ファイル所有者:"
{ "${!owners[@]}" の i の場合; する
printf "%-10s: %5d ファイル\n" "$i" ${owners["$i"]} 完了 } | 選別
echo
# グループをリストする
echo "ファイル グループの所有者:"
{ "${!groups[@]}" の i の場合; する
printf "%-10s: %5d ファイル\n" "$i" ${groups["$i"]} 完了 } | 選別
# 所有者のリストを表示する
echo "ファイル所有者:"
{ "${!owners[@]}" の i の場合; する
printf "%-10s: %5d ファイル\n" "$i" ${owners["$i"]} 完了 } | 選別
echo
# グループをリストする
echo "ファイル グループの所有者:"
{ "${!groups[@]}" の i の場合; する
printf "%-10s: %5d ファイル\n" "$i" ${groups["$i"]} 完了 } | 選別
このスクリプトの仕組みを見てみましょう。
ライン5: 連想配列は次のように作成する必要があります。 宣言する を使用したコマンド -A
オプション。 このスクリプトでは、次のように XNUMX つの配列を作成します。
files には、ファイル名でインデックス付けされたディレクトリ内のファイルの名前が含まれます。 file_group には、ファイル名でインデックス付けされた各ファイルのグループ所有者が含まれます。 file_owner には、ファイル名でインデックス付けされた各ファイルの所有者が含まれます。 groups には、インデックス付けされたグループ所有者に属するファイルの数が含まれます。インデックス付き所有者に属するファイルの数が含まれます
行 7 ~ 10: 有効なディレクトリ名が位置パラメータとして渡されたかどうかをチェックします。 そうでない場合は、使用法メッセージが表示され、スクリプトは終了ステータス 1 で終了します。
12 ~ 20 行目: ディレクトリ内のファイルをループします。 の使用 STAT コマンドの 13 行目と 14 行目では、ファイル所有者とグループ所有者の名前を抽出し、ファイル名を配列インデックスとして使用して、それぞれの配列に値を割り当てます (16 行目、17 行目)。 同様に、ファイル名自体は ファイル 配列(15行目)。
18 ~ 19 行目: ファイル所有者とグループ所有者に属するファイルの合計数が XNUMX つ増加します。
22 ~ 27 行目: ファイルの一覧が出力されます。 これは、「${array[@]}」パラメータ展開を使用して行われます。これは、各要素が個別の単語として扱われる配列要素のリスト全体に展開されます。 これにより、ファイル名にスペースが埋め込まれている可能性が考慮されます。 また、ループ全体が中括弧で囲まれており、グループ コマンドを形成していることにも注意してください。 これにより、ループの出力全体をパイプで渡すことができます。 sort 指示。 これは、配列要素の展開がソートされないために必要です。
行 29 ~ 40: これら XNUMX つのループは、"${!
array[@]}" 展開。配列要素のリストではなく、配列インデックスのリストに展開されます。