부분 이름으로 파일 범위를 선택하는 방법

부분 이름으로 파일 범위를 선택하는 방법

복사, 이동 등에 사용할 파일 이름의 일부를 사용하여 다양한 파일을 선택하고 싶습니다.

무작위 예시 목록:

  1. 알파1a
  2. 알파2aa
  3. alpha3abc
  4. 브라보A1
  5. 브라보B2bb
  6. 백인
  7. 델타A1fdfd
  8. 델타A2다파
  9. 델타A2222
  10. 델타C1
  11. ... (다른 파일 묶음)

alpha2*에서 deltaA*로 이동하는 명령을 실행하고 싶습니다. 그러면 목록에서 2-9가 선택됩니다. 이렇게 하면 이름을 기준으로 범위를 선택할 수 있고 실제로 파일이 몇 개 있는지 걱정할 필요가 없으며 추가 항목도 얻을 수 없습니다.

답변1

start=alpha2*
end=deltaA*

for file in *
do
    if [[ $file > $start && ( $file < $end || $file == $end ) ]]; then
        echo $file
    fi
done

에코 대신 파일을 배열에 저장할 수 있습니다.

array+=($file)

그런 다음 배열을 사용하여 파일을 복사하거나 이동하거나 for 루프 내에서 명령을 수행하면 됩니다.

답변2

쉘 프로그래밍은 사전 편찬 비교에 그리 좋지 않습니다. Bash, ksh 또는 zsh에서는 다음을 사용할 수 있습니다.< 조건부 연산자두 문자열을 비교합니다(POSIX sh에는 숫자 비교만 있습니다).

run_in_range () {
  start_at="$1"; end_before="$2"; command="$3"; shift 3
  for item do
    if [[ ! ($x < $start_at) && ($x < $end_before) ]]; then
      "$command" "$item"
    fi
  done
}
run_in_range alpha2 deltaB some_command *

첫 번째 제외 항목을 두 번째 인수로 사용했다는 점에 유의하세요. 는 deltaB로 시작하는 모든 문자열 뒤에 오는 가장 작은 문자열입니다 deltaA. 인수로 전달하려면 deltaA다음과 같이 하면 됩니다.

run_in_inclusive_range () {
  start_at="$1"; end_on_prefix="$2"; command="$3"; shift 3
  for item do
    if [[ ! ($x < $start_at) && ($x < $end_on_prefix || $x == "$end_on_prefix"*) ]]; then
      "$command" "$item"
    fi
  done
}
run_in_inclusive_range alpha2 deltaA some_command *

이 코드는 와일드카드의 순서에 의존하지 않습니다. 항목 목록이 정렬되지 않은 경우에도 작동합니다. 이렇게 하면 코드가 더욱 강력해지지만 전체 목록을 거쳐야 하기 때문에 약간 느려집니다.

POSIX 기능에만 의존하는 대체 접근 방식은 다음과 같습니다. sort문자열 비교를 수행하는 데 사용됩니다 . 이는 항목에 개행 문자가 없다고 가정합니다. 이 기능은 및 globbing의 기본 설정을 복원합니다 IFS(주변 설정을 복원하는 것은 가능하지만 성가시게 어렵습니다).

run_in_range () {
  IFS='
'; set -f
  start_at="$1"; end_before="$2"; command="$3"; shift 3
  set $({
          printf '%s1\n' "$@"
          printf '%s0\n' "$start_at" "$end_before"
        } | sort | sed '/0$/,/0$/ s/1$//p')
  unset IFS; set +f
  for item do
    "$command" "$item"
  done
}

설명:

  1. 추가된 항목 1과 추가된 경계를 포함하는 목록을 작성합니다 0.
  2. 목록을 정렬합니다.
  3. 두 경계선( 로 끝나는 줄 0) 사이의 선을 인쇄합니다. 단, 로 끝나는 줄 1(즉, 항목)만 인쇄하고 후행 1.

답변3

문제는 생각보다 해결하기가 더 간단한 것 같습니다.

한 줄에 파일 하나씩 목록을 가져오는 방법이 있다고 가정해 보겠습니다.
현재 디렉토리의 경우:

list="$(printf '%s\n' *)"

목록에 제한을 추가하고 정렬하면 됩니다.

nl='
'
lim1="alpha2"
lim2="deltaA"

echo -- "$list""$nl""$lim1""$nl""$lim2" | sort

그런 다음 lim1에서 인쇄를 시작하고(lim1 및 lim2가 기존 파일 이름과 일치하지 않도록 주의) lim2에서 중지합니다.

또한 간단하게 하려면 인쇄하려는 파일 바로 앞의 가장 짧은 문자열과 선택해야 하는 마지막 파일 바로 뒤에 정렬되는 가장 짧은 문자열을 선택하세요.

유용한 것은 배타적 목록(제한을 포함하지 않는 목록)
이지만 두 가지 솔루션이 모두 제공됩니다.

기본 값:

list="$(printf '%s\n' *)"

lim1=alpha2
lim2=deltaA

포함 목록을 위한 awk 솔루션:

echo "awk----------------inclusive"
echo "$list""$nl""$lim1""$nl""$lim2" | sort |
    awk -v lim1="$lim1" -v lim2="$lim2" '$0==lim1,$0==lim2{print}'

독점 목록에 대한 awk 솔루션:

echo "awk----------------exclusive"
echo "$list""$nl""$lim1""$nl""$lim2" | sort |
    awk -v lim1="$lim1" -v lim2="$lim2" '$0==lim1{p=1;next};$0==lim2{p=0};p'

포함 목록을 위한 셸 솔루션:

echo "shell---------------inclusive"
show=0
echo "$list""$nl""$lim1""$nl""$lim2" | sort |
    while IFS="$nl" read -r line; do
        [ "$line" = "$lim1" ] && show=1
        [ "$show" = "1"     ] && printf '%s\n' "$line"
        [ "$line" = "$lim2" ] && show=0
    done

그리고 쉘을 위한 독점적인 솔루션:

show=0
echo "$list""$nl""$lim1""$nl""$lim2" | sort |
    while read -r line; do
        [ "$line" = "$lim2" ] && show=0
        [ "$show" = "1"     ] && printf '%s\n' "$line"
        [ "$line" = "$lim1" ] && show=1
    done

관련 정보