스크립트/명령줄에서 알파벳 순서 등을 기준으로 현재 디렉터리에서 파일의 하위 범위를 선택하는 방법은 무엇입니까?

스크립트/명령줄에서 알파벳 순서 등을 기준으로 현재 디렉터리에서 파일의 하위 범위를 선택하는 방법은 무엇입니까?

파일 관리자에서는 일반적으로 파일을 선택한 다음 Shift다른 파일을 길게 선택할 수 있습니다. 그 사이의 모든 파일이 선택됩니다.

나는 하고 싶다 bash/ zsh이것과 동등하다.

예: 2개의 파일 이름을 지정하고 싶습니다. 각 파일 이름은 중간에 있습니다(알파벳 순서 - ls출력 방식).

및 기타 와일드카드 옵션을 알고 있지만 ? {} *이름이 매우 혼란스러운 파일에 사용할 수 있기를 바랍니다.

예를 들어:주어진 파일

$ ls
aoeitoae.txt
oaeistn.txt
oaie.txt
paeoai.txt
sotaoe.txt

다음과 같은 명령을 실행하여 다음을 얻고 싶습니다 rm aoeitoae.txt-oaie.txt.

$ ls
paeoai.txt
sotaoe.txt

이 목표를 어떻게 달성할 수 있나요?

답변1

이 답변은 주로 zsh에 대한 것입니다. 대부분의 작업은 bash에서는 쉽게 수행할 수 없습니다.

많은 일반적인 상황에서 사용할 수 있습니다.와일드카드. 특히:

  • 모든 것이 함께 제공됩니다고정 접두사:foo-*
  • 모든 것이 함께 제공됩니다고정 접두사 뒤에 범위 내의 다른 문자가 옵니다.: ( , , 를 foo[b-m]*포함 하지만 또는 제외 )foobarfoodfoomz1fooarfoon
  • 특정 범위 내의 숫자: IMG-<7-42>.*(포함 IMG-8.PNGIMG-0042.JPG제외 IMG-77.JPG)

그리고글로벌 예선, 식별하는 간단한 방법이 있습니다.범위이지만 개수가 필요함: 파일이 무엇이든 상관없이 foo*([1,3])나열된 처음 3개 파일과 일치합니다 foo*(3개 미만인 경우 모든 파일과 일치). foo*(om[1,3])이는 로 시작하는 이름 일치 와 같은 정렬이 완료된 후에 발생합니다 foo.

zsh에게 숫자를 알아내도록 요청할 수 있습니다. 두 단계로 수행합니다. 먼저 모든 일치 항목을 배열에 넣은 다음 다음을 사용합니다.아래 첨자 기호 i( 와일드카드 일치를 방지하려는 I경우 e): 요소 간 배열 부분(포함 $a[$a[(i)foo],$a[(I)bar]])이거나 존재하지 않는 경우 비어 있습니다.$afoobarfoobar

a=(*.txt(oL))
# List the files that appear between small.txt and large.txt in a listing by size.
# Note that files that have the same size as one of the bounds may or may not be included.
echo $a[$a[(I)small.txt],$a[(I)large.txt]]

그래서 이것은 구현하는 함수입니다.질문의 요구 사항을 완전히 충족합니다.(정확한 구문을 제외하고는 이 작업을 수행할 수 없습니다):

# Usage: select_range FROM TO WILDCARD_PATTERN
# Sets the array $s to the files matching PATTERN from FROM to TO inclusive.
function select_range {
  if (($# < 2)); then
    echo >&2 "select_range: missing range arguments"
    return 120
  fi
  local from=$1 to=$2
  shift 2
  from=$@[(ie)$from]
  if ((from == 0)); then
    echo >&2 "select_range: not matched: $from"
  fi
  to=$@[(Ie)$to]
  if ((to == 0)); then
    echo >&2 "select_range: not matched: $from"
  fi
  s=($@[$from,$to])
}

용법:select_range aoeitoae.txt oaie.txt * && rm $s

glob e한정자를 사용하면 임의의 코드를 작성하여 결과를 필터링할 수 있지만 약간 다루기 어려워지기 시작했습니다. 복잡한 경우에는 인용이 까다로울 수 있습니다. 단순화를 위해 '구분 기호(백슬래시로 인용해야 함)로 사용하고 필터 코드를 작은따옴표로 묶어 패턴이 다음과 같습니다 foo-*(e\''code goes here'\'). (인용이 너무 복잡해지면 함수를 작성하고 한정자를 사용하세요 +.) 필터링 aoeitoae.txt전과 필터링 전의 파일oaie.txt 사전순으로: *(e\''! [[ $REPLY < aoeitoae.txt || $REPLY > oaie.txt ]]'\').

필터에서 수행된 비교는 반드시 와일드카드 확장과 동일한 순서를 사용하지는 않습니다. 예를 들어, thanks 한정자는 foo-*(n)앞에 나열되어 있지만 문자열 비교에서는foo-9foo-10n[[ foo-9 > foo-10 ]]가정 어구정수 하위 문자열의 수치 비교 와 유사한 >연산자입니다 . 하나 만들고 싶다면문자열과 숫자로 정렬된 정수 부분의 비교,당신은 그것을 사용할 수 있습니다n 매개변수 확장 플래그배열을 정렬하고 중간에 일치하는 이름이 유지되는지 확인합니다. , , , ... *(ne\''a=(b11r $REPLY f10o); [[ $a[2] == "${${(@n)a}[2]}" ]]'\'))는 포함 하지만 , , ... 은 포함하지 않습니다.b101rb11sd1f02ob9rf011

날짜별로 파일을 일치시키는 경우 조건을 사용할 수 있습니다 (파일은 자체 -nt파일보다 최신이 아님).*(ome\''! [[ $REPLY -ot from || $REPLY -nt to ]]'\')사이에 수정된 파일의 수정 시간 from과 의 수정 시간 to(포함)입니다.

답변2

Bash 기능을 사용하세요:

sfiles ()
(
    # run this in a subshell, so we don't have to care if nullglob/dotglob were enabled or not
    [ $# -eq 0 ] && exit
    
    local nullsep=0
    if [ "$1" = "-0" ]; then
        nullsep=1; shift
    fi
    local first=$1
    shift $(($# -1))
    local last=$1
    local files=( )

    shopt -s nullglob dotglob
    for i in *; do
        # first argument found or array not empty?
        if [ "$i" = "$first" ] || [ "${#files[@]}" -ne 0 ]; then
            files+=( "$i" )
        fi
        # last argument found? break loop
        [ "$i" = "$last" ] && break
    done

    if [ "${#files[@]}" -gt 0 ]; then
        [ "$nullsep" -eq 1 ] && 
            printf '%s\0' "${files[@]}" ||
            printf '%s\n' "${files[@]@Q}"
    fi
)

첫 번째 인수와 마지막 인수(포함) 사이의 모든 파일을 출력합니다.

예:

$ ls -A
 btjhyyxrlv.txt    otewagahzp.txt       .xxx
 crlcsbzizl.txt    ssffszhdmp.txt      'zdjtgahx q.txt'
 hgiagchkgt.txt   'tt'$'\t''aa.txt'    'zmwik zhur.txt'
 jusupbivit.txt    umikyfucgu.txt      'z otmleqlq.txt'
' kcyigyurc.txt'  ' upvpntdfv.txt'      .zzz
 kfthnpgrxm.txt   'uu'$'\t\t''aa.txt'
 lgzsmquxwj.txt    wlwexgzohs.txt
$ sfiles c* k*
'crlcsbzizl.txt'
'hgiagchkgt.txt'
'jusupbivit.txt'
' kcyigyurc.txt'
'kfthnpgrxm.txt'
$ sfiles .xxx .zzz
'.xxx'
'zdjtgahx q.txt'
'zmwik zhur.txt'
'z otmleqlq.txt'
'.zzz'
$ LC_ALL=C sfiles .xxx .zzz
'.xxx'
'.zzz'

잘못된 순서입니다. 아무것도 반환하지 않습니다.

$ sfiles .zzz .xxx

선택한 파일을 삭제하려면 다음 명령을 사용하십시오 xargs.

$ sfiles .xxx .zzz | xargs rm

탭이나 줄 바꿈이 있는 파일 이름의 경우 -0bash 인용 없이 null로 구분된 출력의 첫 번째 인수로 옵션을 추가합니다.

$ sfiles -0 tt* uu* | xargs -0 ls
'tt'$'\t''aa.txt'  ' upvpntdfv.txt'
 umikyfucgu.txt    'uu'$'\t\t''aa.txt'

답변3

이 작업을 수행하기 위해 자신만의 셸 함수를 작성할 수 있습니다. 모든 파일 목록을 가져오고 첫 번째 파일 이름 앞의 모든 파일과 두 번째 파일 이름 뒤의 모든 파일을 삭제합니다. 대략적으로 말하면 zsh에서는 이것이 bash에서 더 짜증날 것이라고 생각하기 때문입니다.

#!/usr/bin/zsh
filerange() {
  # variable "reply" is an array
  typeset -ag reply
  reply=("$1")
  # don't get upset if nothing matches
  setopt nullglob

  # get a complete list of candidate files
  #allfiles=*(^/^on) 
  #         ^--------- *   glob
  #          ^----^--- (…) glob modifiers within parentheses
  #           ^------- ^   invert match
  #            ^------ /   match directories (inverted: match all *but* dirs)
  #             ^----- ^   invert sort order (uninvert the above inversion)
  #              ^---- o   order by:
  #               ^--- n    character values of name
  for fname in *(on^/); do
    [[ ( "$2" > "${fname}" && "${fname}" > "$1" ) ]] \
    && reply+=("${fname}")
  done
  reply+=("$2")
}

$reply이는 예를 들어 사용할 수 있는 멋지고 "안전한" 배열을 제공합니다 for.

# prepare a test dir
mkdir /tmp/testdir
cd /tmp/testdir
sudo mknod blockdev b 1 1
sudo mknod chardev c 1 1
mkdir dir
mkfifo fifo
touch file
touch "file with spaces"
touch "file with\nnewlines"
touch "last file"
touch "ok one more file"
ln -s blockdev symlink

# This will look funny, because there's a file name with a new line in there
echo *

# Let's try this:
filerange chardev "last file"
# We're expecting to get all files from (incl) chardev to (incl) last file,
# but not `dir`, as that's a directory
for f in ${reply}; do;
  echo "entry: ${f}"
done

parallel물론, 이러한 파일(예: for 또는 ) 을 인쇄하고 싶다면 xargs옵션을 -0Freddy의 파일로 사용하는 함수를 작성하세요.좋은 대답일러스트는 탁월한 선택입니다! 이 함수는 매우 간단합니다. 'ing 루프에서 호출할 수 있고 from을 filerange처리합니다 .$replyprintffor

답변4

이것은 완전한 대답은 아니지만 awk사용할 수 있는 훌륭한 범위 연산자가 있다는 점을 언급하고 싶었습니다.

$ ls | awk '/^aoeitoae\.txt$/,/^oaie\.txt$/ { print }'
aoeitoae.txt
oaeistn.txt
oaie.txt

awk코드는 첫 번째 정규식과 일치하는 첫 번째 입력 줄부터 시작하여 두 번째 정규식과 일치하는 첫 번째 입력 줄로 끝나는 입력 줄을 인쇄합니다.

일치는 정규식을 사용하며 이 예에서는 인용되지 않으므로 파일 이름에 공백이나 기타 이상한 문자가 포함되어 예상치 못한 결과가 발생할 수 있습니다.

그리고아마도다음과 같은 텍스트 기반 파일 관리자를 사용해 보고 싶습니다.자정 사령관.

관련 정보