Bash 配列から一致する要素を削除する方法

ShellShellBeginner
オンラインで実践に進む

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

このチュートリアルでは、シェルプログラミングの基本的なスキルである、Bash 配列から一致する要素を削除するプロセスを説明します。配列を使用すると、単一の変数に複数の値を格納できるため、スクリプトでデータのコレクションを管理するために不可欠です。

このチュートリアルを終える頃には、特定の条件に一致する要素を削除することに焦点を当て、Bash 配列を効果的に作成、操作、および変更する方法を理解できるようになります。これらのスキルは、さまざまな自動化タスクのために、より効率的で強力な Bash スクリプトを作成するのに役立ちます。

Bash 配列の作成と操作

配列から要素を削除する方法を学ぶ前に、まず Bash 配列の作成と操作方法を理解しましょう。

最初の配列の作成

LabEx 環境でターミナルを開きます。まず、果物のシンプルな配列を作成することから始めましょう。

fruits=("apple" "banana" "cherry" "orange" "apple")

このコマンドは、5 つの要素を含むfruitsという名前の配列を作成します。"apple"が 2 回現れていることに注意してください。これは、後で一致する要素を削除する練習をするときに役立ちます。

配列要素の表示

配列内のすべての要素を表示するには、以下を使用します。

echo "${fruits[@]}"

すべての要素を示す出力が表示されるはずです。

apple banana cherry orange apple

特定の要素を表示するには、そのインデックスを指定できます(Bash では配列のインデックスは 0 から始まることを覚えておいてください)。

echo "${fruits[0]}" ## 最初の要素を表示: apple
echo "${fruits[1]}" ## 2番目の要素を表示: banana

配列の長さを確認する

配列にいくつの要素があるかを確認するには、以下を使用します。

echo "${#fruits[@]}"

これは5を出力するはずです。これは、fruits 配列内の要素の総数です。

配列への要素の追加

+=演算子を使用して、既存の配列に新しい要素を追加できます。

fruits+=("grape")
echo "${fruits[@]}"

出力には、最後に"grape"が含まれるはずです。

apple banana cherry orange apple grape

作業ファイルの作成

配列操作を練習するファイルを作成しましょう。WebIDE で、ファイルエクスプローラーパネルの「New File」アイコンをクリックして、/home/labex/projectディレクトリにarray_operations.shという名前の新しいファイルを作成します。

ファイルに次のコードを追加します。

#!/bin/bash

## Define our fruits array
fruits=("apple" "banana" "cherry" "orange" "apple" "grape")

## Display all elements
echo "All fruits in the array:"
echo "${fruits[@]}"

## Display the number of elements
echo "Number of fruits: ${#fruits[@]}"

## Display the first element
echo "First fruit: ${fruits[0]}"

ファイルを保存し(Ctrl+S またはメニューを使用)、実行可能にします。

chmod +x /home/labex/project/array_operations.sh

次に、スクリプトを実行します。

./array_operations.sh

配列要素、カウント、および最初の要素を示す出力が表示されるはずです。

All fruits in the array:
apple banana cherry orange apple grape
Number of fruits: 6
First fruit: apple

おめでとうございます!最初の Bash 配列を作成し、基本的な操作を実行しました。次のステップでは、配列から特定の要素を削除する方法を学びます。

for ループと unset を使用した要素の削除

Bash 配列の基本を理解したところで、配列から一致する要素を削除する方法を探ってみましょう。forループとunsetコマンドを使用した、最も簡単な方法から始めます。

unset コマンドの理解

Bash のunsetコマンドを使用すると、インデックスを指定して配列から要素を削除できます。たとえば、fruits配列の最初の要素を削除するには、次のようにします。

unset fruits[0]
echo "${fruits[@]}"

これを実行すると、次のように出力されます。

banana cherry orange apple grape

最初の"apple"が削除されたことに注意してください。ただし、配列のインデックスは自動的に並べ替えられません。これは、要素を削除した後、配列のインデックスシーケンスに「ギャップ」が生じる可能性があることを意味します。

for ループを使用した一致する要素の削除

fruits配列から"apple"のすべての出現を削除する新しいスクリプトを作成しましょう。WebIDE で、/home/labex/projectディレクトリにremove_elements.shという名前の新しいファイルを作成します。

#!/bin/bash

## Define our fruits array
fruits=("apple" "banana" "cherry" "orange" "apple" "grape")

echo "Original array: ${fruits[@]}"

## Loop through the array indices in reverse order
for ((i = ${#fruits[@]} - 1; i >= 0; i--)); do
  if [ "${fruits[$i]}" == "apple" ]; then
    unset "fruits[$i]"
  fi
done

## Print the modified array
echo "Array after removing 'apple': ${fruits[@]}"

## Reindex the array to remove gaps (optional)
fruits=("${fruits[@]}")
echo "Array after reindexing: ${fruits[@]}"

ファイルを保存し、実行可能にします。

chmod +x /home/labex/project/remove_elements.sh

スクリプトを実行します。

./remove_elements.sh

次のような出力が表示されるはずです。

Original array: apple banana cherry orange apple grape
Array after removing 'apple': banana cherry orange grape
Array after reindexing: banana cherry orange grape

コードの理解

スクリプトが行うことを見てみましょう。

  1. "apple"の 2 つのインスタンスを含む、さまざまな果物の名前を持つfruitsという配列を定義しました。
  2. 配列インデックスを逆順にループしました(要素を削除する際のインデックスシフトの問題を回避するため)。
  3. 各要素について、それが"apple"と等しいかどうかを確認し、等しい場合は削除しました。
  4. 一致するすべての要素を削除した後、インデックスシーケンスのギャップをなくすために配列を再インデックスしました。

配列を逆順にループしたことに注意してください。これは、要素を削除する際に重要です。なぜなら、前方へ反復しながら要素を削除すると、残りの要素のインデックスがシフトし、一部の要素がスキップされる可能性があるからです。

さまざまな値での実験

ユーザーが指定した任意の果物を削除できるように、スクリプトを変更しましょう。remove_elements.shファイルを次のように編集します。

#!/bin/bash

## Define our fruits array
fruits=("apple" "banana" "cherry" "orange" "apple" "grape")

## If no argument provided, default to removing "apple"
fruit_to_remove=${1:-"apple"}

echo "Original array: ${fruits[@]}"
echo "Removing: $fruit_to_remove"

## Loop through the array indices in reverse order
for ((i = ${#fruits[@]} - 1; i >= 0; i--)); do
  if [ "${fruits[$i]}" == "$fruit_to_remove" ]; then
    unset "fruits[$i]"
  fi
done

## Print the modified array
echo "Array after removing '$fruit_to_remove': ${fruits[@]}"

## Reindex the array to remove gaps
fruits=("${fruits[@]}")
echo "Array after reindexing: ${fruits[@]}"

ファイルを保存し、さまざまな引数で実行します。

./remove_elements.sh banana

"banana"が削除されたことを示す出力が表示されるはずです。

Original array: apple banana cherry orange apple grape
Removing: banana
Array after removing 'banana': apple cherry orange apple grape
Array after reindexing: apple cherry orange apple grape

配列内の他の果物の名前で試してみてください。

./remove_elements.sh orange

素晴らしい!for ループと unset コマンドを使用して、Bash 配列から一致する要素を削除する方法を学びました。次のステップでは、配列から要素を削除するための代替方法を探ります。

要素を削除するための代替方法

for ループと unset は、配列から要素を削除するための一般的なアプローチですが、Bash には、特定の状況でより簡潔または効率的な他の方法も用意されています。2 つの代替アプローチを探ってみましょう。

方法 1:フィルタリングされた要素を持つ新しい配列の作成

既存の配列から要素を削除する代わりに、保持したい要素のみを含む新しい配列を作成できます。このアプローチでは、要素を削除した後に配列を再インデックスする必要がありません。

/home/labex/projectディレクトリにfilter_array.shという名前の新しいファイルを作成します。

#!/bin/bash

## Define our fruits array
fruits=("apple" "banana" "cherry" "orange" "apple" "grape")

## If no argument provided, default to removing "apple"
fruit_to_remove=${1:-"apple"}

echo "Original array: ${fruits[@]}"
echo "Removing: $fruit_to_remove"

## Create a new array without the matching elements
declare -a filtered_fruits
for fruit in "${fruits[@]}"; do
  if [ "$fruit" != "$fruit_to_remove" ]; then
    filtered_fruits+=("$fruit")
  fi
done

## Print the filtered array
echo "Array after removing '$fruit_to_remove': ${filtered_fruits[@]}"

ファイルを保存し、実行可能にします。

chmod +x /home/labex/project/filter_array.sh

スクリプトを実行します。

./filter_array.sh

次のような出力が表示されるはずです。

Original array: apple banana cherry orange apple grape
Removing: apple
Array after removing 'apple': banana cherry orange grape

方法 2:配列置換パターンを使用する

Bash には、配列をフィルタリングするために使用できる強力なパラメータ展開構文が用意されています。この方法を新しいスクリプトで実装してみましょう。

/home/labex/projectディレクトリにpattern_remove.shという名前のファイルを作成します。

#!/bin/bash

## Define our fruits array
fruits=("apple" "banana" "cherry" "orange" "apple" "grape")

## If no argument provided, default to removing "apple"
fruit_to_remove=${1:-"apple"}

echo "Original array: ${fruits[@]}"
echo "Removing: $fruit_to_remove"

## Create a temporary array to store valid indices
declare -a indices=()
for i in "${!fruits[@]}"; do
  if [ "${fruits[$i]}" != "$fruit_to_remove" ]; then
    indices+=("$i")
  fi
done

## Create the filtered array using the valid indices
declare -a filtered_fruits=()
for i in "${indices[@]}"; do
  filtered_fruits+=("${fruits[$i]}")
done

## Print the filtered array
echo "Array after removing '$fruit_to_remove': ${filtered_fruits[@]}"

ファイルを保存し、実行可能にします。

chmod +x /home/labex/project/pattern_remove.sh

スクリプトを実行します。

./pattern_remove.sh grape

"grape"が削除された出力が表示されるはずです。

Original array: apple banana cherry orange apple grape
Removing: grape
Array after removing 'grape': apple banana cherry orange apple

方法の比較

3 つのすべての方法を比較するサマリスクリプトを作成しましょう。/home/labex/projectディレクトリにcompare_methods.shという名前のファイルを作成します。

#!/bin/bash

## Define our test array
fruits=("apple" "banana" "cherry" "orange" "apple" "grape")
fruit_to_remove=${1:-"apple"}

echo "Original array: ${fruits[@]}"
echo "Removing: $fruit_to_remove"
echo ""

## Method 1: Using for loop and unset
echo "Method 1: Using for loop and unset"
declare -a fruits_copy=("${fruits[@]}")
for ((i = ${#fruits_copy[@]} - 1; i >= 0; i--)); do
  if [ "${fruits_copy[$i]}" == "$fruit_to_remove" ]; then
    unset "fruits_copy[$i]"
  fi
done
fruits_copy=("${fruits_copy[@]}")
echo "Result: ${fruits_copy[@]}"
echo ""

## Method 2: Creating a new filtered array
echo "Method 2: Creating a new filtered array"
declare -a filtered_fruits=()
for fruit in "${fruits[@]}"; do
  if [ "$fruit" != "$fruit_to_remove" ]; then
    filtered_fruits+=("$fruit")
  fi
done
echo "Result: ${filtered_fruits[@]}"
echo ""

## Method 3: Using array indices
echo "Method 3: Using array indices"
declare -a indices_filtered=()
for i in "${!fruits[@]}"; do
  if [ "${fruits[$i]}" != "$fruit_to_remove" ]; then
    indices_filtered+=("${fruits[$i]}")
  fi
done
echo "Result: ${indices_filtered[@]}"

ファイルを保存し、実行可能にします。

chmod +x /home/labex/project/compare_methods.sh

削除するさまざまな果物でスクリプトを実行します。

./compare_methods.sh banana

3 つのすべての方法の比較が表示されるはずです。

Original array: apple banana cherry orange apple grape
Removing: banana

Method 1: Using for loop and unset
Result: apple cherry orange apple grape

Method 2: Creating a new filtered array
Result: apple cherry orange apple grape

Method 3: Using array indices
Result: apple cherry orange apple grape

3 つのすべての方法は同じ目標を達成しますが、それぞれに利点があります。

  • 方法 1(for ループと unset を使用)は、元の配列をインプレースで変更します
  • 方法 2(新しい配列を作成する)は、多くの場合、より明確であり、インデックスシフトの問題を回避します
  • 方法 3(配列インデックスを使用する)は、元の配列を保持する必要がある場合に役立ちます

特定のユースケースとコーディングスタイルに最適な方法を選択してください。

実践的な演習:ファイルクリーンアップスクリプトの構築

Bash 配列から要素を削除するためのさまざまな方法を理解したところで、この知識を実践的な状況に適用してみましょう。特定のファイルタイプをフィルタリングすることにより、ディレクトリをクリーンアップするのに役立つスクリプトを作成します。

ファイルクリーンアップのチャレンジ

さまざまなファイルタイプ(テキストファイル、画像、ドキュメント)を含むディレクトリがあり、特定のファイルタイプを選択的に削除したいとします。Bash 配列を使用してこれらのファイルを管理し、配列フィルタリングに関する知識を適用します。

ステップ 1:サンプルファイルを使用したテストディレクトリの設定

まず、いくつかのサンプルファイルを使用してテストディレクトリを作成しましょう。ターミナルを開き、次を実行します。

mkdir -p /home/labex/project/test_files
cd /home/labex/project/test_files

## Create some sample files
touch file1.txt file2.txt document1.pdf document2.pdf image1.jpg image2.jpg script.sh config.yaml

ファイルが作成されたことを確認します。

ls -la

作成したばかりのサンプルファイルのリストが表示されるはずです。

ステップ 2:ファイルクリーンアップスクリプトの作成

次に、配列操作を使用してファイルをフィルタリングするスクリプトを作成しましょう。/home/labex/projectディレクトリにcleanup_files.shという名前の新しいファイルを作成します。

#!/bin/bash

## Directory to scan
target_dir=${1:-"/home/labex/project/test_files"}
## File extension to filter out
extension_to_remove=${2:-"txt"}

echo "Scanning directory: $target_dir"
echo "Will remove files with extension: $extension_to_remove"

## Change to the target directory
cd "$target_dir" || {
  echo "Directory not found!"
  exit 1
}

## Get all files in the directory
all_files=(*)

echo "All files: ${all_files[@]}"

## Create an array to store files to keep
declare -a files_to_keep=()

## Filter out files with the specified extension
for file in "${all_files[@]}"; do
  if [[ "$file" != *.$extension_to_remove ]]; then
    files_to_keep+=("$file")
  fi
done

echo "Files to keep: ${files_to_keep[@]}"

## Create an array of files to remove
declare -a files_to_remove=()
for file in "${all_files[@]}"; do
  if [[ "$file" == *.$extension_to_remove ]]; then
    files_to_remove+=("$file")
  fi
done

echo "Files that would be removed: ${files_to_remove[@]}"

## Ask for confirmation before removing
echo
echo "This script is in simulation mode and won't actually delete any files."
echo "In a real scenario, you would ask for confirmation before deletion:"
echo "read -p 'Are you sure you want to remove these files? (y/n): ' confirm"
echo "if [ \"\$confirm\" == \"y\" ]; then rm \"\${files_to_remove[@]}\"; fi"

ファイルを保存し、実行可能にします。

chmod +x /home/labex/project/cleanup_files.sh

ステップ 3:ファイルクリーンアップスクリプトの実行

次に、スクリプトを実行して、ファイルがどのように識別およびフィルタリングされるかを確認しましょう。

./cleanup_files.sh

これにより、削除されるファイル(.txt拡張子を持つファイル)を示す出力が表示されるはずです。

さまざまなファイル拡張子で試してみてください。

./cleanup_files.sh /home/labex/project/test_files pdf

これにより、.pdf拡張子を持つファイルが削除されるファイルとして表示されます。

ステップ 4:バッチ処理によるスクリプトの強化

複数のファイル拡張子を一度に処理するようにスクリプトを強化しましょう。/home/labex/projectディレクトリにadvanced_cleanup.shという名前の新しいファイルを作成します。

#!/bin/bash

## Directory to scan
target_dir=${1:-"/home/labex/project/test_files"}

## Default extensions to remove
extensions=("txt" "pdf")

## Override default extensions if provided as arguments
if [ $## -gt 1 ]; then
  extensions=("${@:2}")
fi

echo "Scanning directory: $target_dir"
echo "Will filter files with these extensions: ${extensions[@]}"

## Change to the target directory
cd "$target_dir" || {
  echo "Directory not found!"
  exit 1
}

## Get all files in the directory
all_files=(*)

echo "All files: ${all_files[@]}"

## Create an array to store files to keep
declare -a files_to_keep=()

## Create an array to store files to remove
declare -a files_to_remove=()

## Process each file
for file in "${all_files[@]}"; do
  ## Extract the file extension
  file_ext="${file##*.}"

  ## Check if the file extension is in our list
  should_remove=false
  for ext in "${extensions[@]}"; do
    if [ "$file_ext" == "$ext" ]; then
      should_remove=true
      break
    fi
  done

  ## Add to appropriate array based on whether it should be removed
  if [ "$should_remove" == true ]; then
    files_to_remove+=("$file")
  else
    files_to_keep+=("$file")
  fi
done

echo "Files to keep: ${files_to_keep[@]}"
echo "Files that would be removed: ${files_to_remove[@]}"

echo
echo "This script is in simulation mode and won't actually delete any files."
echo "In a real scenario, you would ask for confirmation before deletion."

ファイルを保存し、実行可能にします。

chmod +x /home/labex/project/advanced_cleanup.sh

拡張子のさまざまな組み合わせで高度なスクリプトを実行します。

./advanced_cleanup.sh /home/labex/project/test_files txt jpg

これにより、削除する.txtファイルと.jpgファイルの両方が識別されます。

これまでに行ったことの理解

この実践的な演習では、次のことを行いました。

  1. さまざまなファイルタイプを持つテスト環境を作成しました
  2. 特定の拡張子を持つファイルを識別するために配列フィルタリングを使用する基本的なスクリプトを構築しました
  3. 複数のファイル拡張子を処理するようにスクリプトを強化しました
  4. 実世界のシナリオで Bash 配列を使用する方法を示しました

この例は、学習した配列操作手法を、ファイル管理やクリーンアップタスクなどの実際の問題に適用できることを示しています。配列をフィルタリングする機能は、Bash スクリプト作成ツールキットの強力なツールです。

まとめ

Bash 配列から一致する要素を削除するこのチュートリアルを修了したことをおめでとうございます。シェルスクリプトの機能を強化する貴重なスキルを習得しました。

  • Bash 配列の作成と操作
  • for ループと unset メソッドを使用した配列からの要素の削除
  • 配列要素をフィルタリングするための代替アプローチ
  • 配列フィルタリング技術を現実世界のファイル管理タスクに適用する

これらのスキルは、Bash スクリプト作成ツールキットの不可欠な部分を形成し、さまざまな自動化タスク、データ処理操作、およびシステム管理業務に適用できます。

このチュートリアルからの主なポイント:

  • Bash 配列は、データのコレクションを保存および処理するための便利な方法を提供します
  • 配列から要素を削除する場合は、インデックスシフトに注意してください
  • 配列をフィルタリングするためのさまざまな方法は、ユースケースに応じて異なる利点があります
  • 配列操作技術は、ファイル管理などの実際の問題を解決するために適用できます

Bash スクリプト作成の旅を続けるにつれて、これらの配列操作スキルは、より効率的で強力なスクリプトを作成する上で非常に役立つことが証明されます。Bash 配列の操作に関する知識をリフレッシュする必要がある場合は、このチュートリアルを遠慮なく参照してください。