Bash 배열에서 일치하는 요소 제거 방법

ShellBeginner
지금 연습하기

소개

이 튜토리얼은 셸 프로그래밍의 기본 기술인 Bash 배열에서 일치하는 요소를 제거하는 과정을 안내합니다. 배열을 사용하면 단일 변수에 여러 값을 저장할 수 있으므로 스크립트에서 데이터 컬렉션을 관리하는 데 필수적입니다.

이 튜토리얼을 마치면 특정 기준과 일치하는 특정 요소를 제거하는 데 중점을 두고 Bash 배열을 효과적으로 생성, 조작 및 수정하는 방법을 이해하게 됩니다. 이러한 기술은 다양한 자동화 작업에 더 효율적이고 강력한 Bash 스크립트를 작성하는 데 도움이 될 것입니다.

Bash 배열 생성 및 작업

배열에서 요소를 제거하는 방법을 배우기 전에 먼저 Bash 배열을 생성하고 작업하는 방법을 이해해 보겠습니다.

첫 번째 배열 생성

LabEx 환경에서 터미널을 엽니다. 먼저 간단한 과일 배열을 만들어 보겠습니다.

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

이 명령은 "fruits"라는 이름의 배열을 생성하며, 5 개의 요소를 포함합니다. "apple"이 두 번 나타나는 것을 주목하세요. 이는 나중에 일치하는 요소를 제거하는 연습을 할 때 유용합니다.

배열 요소 표시

배열의 모든 요소를 보려면 다음을 사용합니다.

echo "${fruits[@]}"

모든 요소를 표시하는 출력을 볼 수 있습니다.

apple banana cherry orange apple

특정 요소를 표시하려면 해당 인덱스를 지정할 수 있습니다 (Bash 에서 배열 인덱스는 0 부터 시작하는 것을 기억하세요).

echo "${fruits[0]}" ## 첫 번째 요소 표시: apple
echo "${fruits[1]}" ## 두 번째 요소 표시: banana

배열 길이 확인

배열에 몇 개의 요소가 있는지 확인하려면 다음을 사용합니다.

echo "${#fruits[@]}"

이것은 5를 출력해야 합니다. 이는 과일 배열의 총 요소 수입니다.

배열에 요소 추가

+= 연산자를 사용하여 기존 배열에 새 요소를 추가할 수 있습니다.

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 루프를 사용하여 일치하는 요소 제거

과일 배열에서 "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" 인스턴스를 포함하여 다양한 과일 이름이 있는 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 는 특정 상황에서 더 간결하거나 효율적일 수 있는 다른 방법을 제공합니다. 두 가지 대체 방법을 살펴보겠습니다.

방법 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

방법 비교

세 가지 방법을 모두 비교하는 요약 스크립트를 만들어 보겠습니다. /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

세 가지 방법을 모두 비교하는 것을 볼 수 있습니다.

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

세 가지 방법 모두 동일한 목표를 달성하지만 각각 장점이 있습니다.

  • 방법 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 배열 작업에 대한 지식을 새로 고쳐야 할 때마다 주저하지 말고 이 튜토리얼을 참조하십시오.