programing

파일을 세는 bash 명령어가 있습니까?

javajsp 2023. 5. 4. 18:39

파일을 세는 bash 명령어가 있습니까?

패턴과 일치하는 파일 수를 세는 bash 명령어가 있습니까?

를 들어,이 과 일치하는 의 수를 : 예 들 어 다 패 수 가 고 려 합 오 니 져 다 를 파 를 일 모 든 의 리 음 터 디 는 렉 턴 일 하 치 과 ▁for 다log*

이 간단한 원라이너는 bash뿐만 아니라 모든 셸에서 작동해야 합니다.

ls -1q log* | wc -l

ls -1q는 공백이나 새 줄과 같은 특수 문자를 포함하더라도 파일당 한 줄을 제공합니다.

출력은 wc -l로 파이프 연결되어 라인 수를 계산합니다.

여기에는 많은 답이 있지만, 일부는 고려하지 않습니다.

  • 공백, 줄 바꿈 또는 제어 문자가 있는 파일 이름
  • (" ▁called▁file(▁file이)▁a포▁thathens▁(imagine-l)
  • 파일숨진파일지, 점시는파일하작경우겨있으는이구본로지▁the,▁hidden파(일)▁files경,if우▁(▁dot있*.loglog*
  • ▁directory()리ies▁that▁director리토토디▁the디렉▁(▁glob)logs 일치하는log*)
  • 빈 디렉토리(즉, 결과는 0)
  • 매우 큰 디렉토리(모두 메모리를 소모할 수 있음)

다음은 이러한 모든 문제를 해결하는 솔루션입니다.

ls 2>/dev/null -Ubad1 -- log* | wc -l

설명:

  • -U 인들원ls, 즉에 전체 가 없음을 합니다.
  • -b이 아닌 문자에 대해 C 이스케이프를 으로 새 이 비래픽문대한자 C이스프인다를로 됩니다. 결정적으로 새 줄이 인쇄되도록 합니다.\n.
  • -a모든 파일, 심지어 숨긴 파일도 출력합니다(글로벌할 때 엄격하게 필요하지 않음).log*숨김 파일 없음)
  • -d디렉토리의 내용을 나열하지 않고 디렉토리를 인쇄합니다.ls보통이라면 할 수 있을 것
  • -1하나의 열에 있는지 확인합니다(ls는 파이프에 쓸 때 자동으로 이 작업을 수행하므로 엄격하게 필요하지 않습니다).
  • 2>/dev/null로그 인 경우 메시지를 . stderr은 0개의 로그 파일을 무시합니다 (: (으)로 표시:shopt -s nullglob원인이 될 것입니다ls대신 전체 작업 디렉토리를 나열합니다.)
  • wc -l하므로, 의 은 다음과 같습니다.ls어떤 시점에서도 기억에 남아있지 않습니다.
  • --하여 " 이 름 구 됩니 분다 명령 과사 여 하--에대주장이않도록에 대한 .ls (경우는에는)log*

이 확장됩니다.log*파일이 많으면 메모리가 소모될 수 있으므로 grep를 통해 실행하는 것이 좋습니다.

ls -Uba1 | grep ^log | wc -l

마지막은 메모리를 많이 사용하지 않고 매우 큰 파일 디렉토리를 처리합니다(서브 셸을 사용하지만).-d현재 디렉터리의 내용만 나열하기 때문에 더 이상 필요하지 않습니다.

재귀 검색의 경우:

find . -type f -name '*.log' -printf x | wc -c

wc -c는 의출 에있문수계산다니합를의 된 문자 를 계산합니다.find,하는 동안에-printf x말한다find 장의 인쇄를 하다x이렇게 등이 하지 않습니다.이렇게 하면 새 줄 등이 포함된 홀수 이름의 파일 문제를 방지할 수 있습니다.

비재귀적 검색의 경우 다음을 수행합니다.

find . -maxdepth 1 -type f -name '*.log' -printf x | wc -c

작업은 안전하게 할 수 공백이 이나 이작을안게전수하있다수. 즉, 있파일이나는니공습백이할행).\n그들의 이름으로) bash:

$ shopt -s nullglob
$ logfiles=(*.log)
$ echo ${#logfiles[@]}

문자 그대로 사용할 수 없도록 설정해야 합니다.*.log에 시대에$logfiles 일치하는 파일이 없는 경우 배열. (안전하게 재설정하는 방법에 대한 예는 'set -x'"실행 취소"하는 방법을 참조하십시오.)

이 질문에 대한 수락된 답변은 틀리지만, 저는 낮은 평가를 받고 있기 때문에 코멘트를 추가할 수 없습니다.

이 질문에 대한 정답은 매트가 제공합니다.

shopt -s nullglob
logfiles=(*.log)
echo ${#logfiles[@]}

허용된 답변의 문제는 wc-l이 줄바꿈 문자의 수를 세고, 'ls-l' 출력에서 단말기에 '?'로 출력해도 세는 것입니다.즉, 파일 이름에 줄 바꿈 문자가 포함되어 있으면 승인된 응답이 실패합니다.제안된 명령을 테스트했습니다.

ls -l log* | wc -l

그리고 이름에 새 줄 문자가 포함된 패턴과 일치하는 파일이 하나만 있더라도 값이 2인 것을 잘못 보고합니다.예:

touch log$'\n'def
ls log* -l | wc -l

중요한 논평

(평판이 부족하여 논평할 수 없음)

BUGGY입니다.

ls -1q some_pattern | wc -l

한다면shopt -s nullglob우연히 설정되면 패턴이 있는 파일뿐만 아니라 모든 일반 파일의 수를 출력합니다(CentOS-8 및 Cygwin에서 테스트됨).다른 무의미한 벌레들이 무엇을 하는지 누가 압니까?ls가지고 계십니까?

이것은 정확하고 훨씬 빠릅니다.

shopt -s nullglob; files=(some_pattern); echo ${#files[@]};

그것은 예상되는 일을 합니다.


And the running times differ.
The 1st: 0.006 on CentOS, and 0.083 on Cygwin (in case it is used with care).
The 2nd: 0.000 on CentOS, and 0.003 on Cygwin.

파일이 많고 우아한 파일을 사용하지 않으려는 경우shopt -s nullglobbash 어레이 솔루션을 사용하면 파일 이름(새 줄이 포함될 수 있음)을 출력하지 않는 한 find 등이 포함될 수 있음).

find -maxdepth 1 -name "log*" -not -name ".*" -printf '%i\n' | wc -l

하면 log하며 "*"로 됩니다..*"이름이 아닙니다.는 중복되지만 "ls"에 대한 기본값은 점 파일을 표시하지 않는 것이지만 찾기 기본값은 점 파일을 포함하는 것입니다.

파일 이름은 명령 간에 전달되지 않기 때문에 이는 올바른 대답이며, 사용자가 던질 수 있는 모든 유형의 파일 이름을 처리합니다.

그데그런.shopt nullglob답은 최고의 답입니다!

여기 이것을 위한 나의 하나의 라이너입니다.

 file_count=$( shopt -s nullglob ; set -- $directory_to_search_inside/* ; echo $#)

셸 함수를 사용하여 이러한 명령을 쉽게 정의할 수 있습니다.이 메서드는 외부 프로그램이 필요하지 않으며 하위 프로세스를 생성하지 않습니다.은 위험한 일을 .ls"특수" 문자(공백, 줄 바꿈, 백슬래시 등)를 구문 분석하고 처리합니다.셸에서 제공하는 파일 이름 확장 메커니즘에만 의존합니다.적어도 sh, bash 및 zsh와 호환됩니다.

은 아라인다음같함정은다의니합수를라고 하는 합니다.count호출된 인수의 수를 출력합니다.

count() { echo $#; }

원하는 패턴을 사용하여 간단히 호출:

count log*

때 셸 " " " " " " " " " " " " " " " " " 이 .nullglob(또는)failglob에서 기본 .zsh)에서 할 때 .다음과 같이 설정할 수 있습니다.

shopt -s nullglob    # for sh / bash
setopt nullglob      # for zsh

셀 항목에 따라 셸 옵션에도 관심이 있을 수 있습니다.dotglob.

유감스럽게도 최소한 bash를 사용하면 이러한 옵션을 로컬로 설정하는 것이 쉽지 않습니다.이러한 설정을 전체적으로 설정하지 않으려면 가장 간단한 해결 방법은 다음과 같이 복잡한 방식으로 기능을 사용하는 것입니다.

( shopt -s nullglob ; shopt -u failglob ; count log* )

구문을 Lightweight 구려는경우하문구복을경▁if우▁thecount log*또는 하위 셸이 생성되지 않도록 하려면 다음과 같이 해킹할 수 있습니다.

# sh / bash:
# the alias is expanded before the globbing pattern, so we
# can set required options before the globbing gets expanded,
# and restore them afterwards.
count() {
    eval "$_count_saved_shopts"
    unset _count_saved_shopts
    echo $#
}
alias count='
    _count_saved_shopts="$(shopt -p nullglob failglob)"
    shopt -s nullglob
    shopt -u failglob
    count'

추가적으로, 이 기능은 더 일반적으로 사용됩니다.예를 들어:

count a* b*          # count files which match either a* or b*
count $(jobs -ps)    # count stopped jobs (sh / bash)

파일 이와 C 프로그램)로하여 ""와 .find그리고.xargs:

find "$FIND_OPTIONS" -exec count {} \+    # count results of a search

-R 옵션을 사용하여 재귀 디렉터리에 있는 파일과 함께 파일을 찾을 수 있습니다.

ls -R | wc -l // to find all the files

ls -R | grep log | wc -l // to find the files which contains the word log

당신은 그렙의 패턴을 사용할 수 있습니다.

저는 이 대답에 대해 많은 생각을 했습니다. 특히 파서하지 않는 것들을 고려했을 때 말입니다.처음에 저는 노력했습니다.

<경고! 작동하지 않음>
du --inodes --files0-from=<(find . -maxdepth 1 -type f -print0) | awk '{sum+=int($1)}END{print sum}'
</경고! 작동하지 않음>

같은 파일 이름만 있으면 작동했습니다.

touch $'w\nlf.aa'

이렇게 파일 이름을 만들면 실패합니다.

touch $'firstline\n3 and some other\n1\n2\texciting\n86stuff.jpg'

저는 마침내 제가 아래에 두고 있는 것을 생각해냈습니다.참고 디렉터리(하위 디렉터리 제외)에 있는 모든 파일의 개수를 가져오려고 했습니다.저는 @Mat과 @Dan_Yard의 답변과 함께 @mogsie에 의해 설정된 요구 사항의 대부분을 가지고 있다고 생각합니다(기억력에 대해서는 잘 모르겠습니다).저는 @mogsie의 답이 옳다고 생각하지만, 저는 항상 구문 분석을 멀리하려고 노력합니다.ls아주 구체적인 상황이 아니라면요

awk -F"\0" '{print NF-1}' < <(find . -maxdepth 1 -type f -print0) | awk '{sum+=$1}END{print sum}'

더 읽기 쉽게:

awk -F"\0" '{print NF-1}' < \
  <(find . -maxdepth 1 -type f -print0) | \
    awk '{sum+=$1}END{print sum}'

이것은 특히 파일을 찾기 위해 공백 및 줄바꿈 문제를 피하기 위해 출력을 null 문자로 구분한 다음 null 문자 수를 계산합니다.파일 수는 끝에 null 문자가 있으므로 null 문자 수보다 1개 적습니다.

OP의 질문에 답하기 위해 고려해야 할 두 가지 경우가 있습니다.

비재귀적 검색:

awk -F"\0" '{print NF-1}' < \
  <(find . -maxdepth 1 -type f -name "log*" -print0) | \
    awk '{sum+=$1}END{print sum}'

재귀 검색입니다.로 내에있것 안에 것은 무엇입니까?-name약간 다른 동작(숨겨진 파일 등)에 대해 매개 변수를 변경해야 할 수 있습니다.

awk -F"\0" '{print NF-1}' < \
  <(find . -type f -name "log*" -print0) | \
    awk '{sum+=$1}END{print sum}'

제가 이 답변에서 언급한 것과 비교하여 이 답변에 대해 의견을 제시하고 싶은 사람이 있다면 말씀해 주십시오.


참고로, 저는 답을 얻으면서 이 생각의 과정에 도달했습니다.

이것은 표준 POSIX 셸 문법으로 수행할 수 있습니다.

여기 간단한 것이 있습니다.count_entries함수:

#!/usr/bin/env sh

count_entries()
{
  # Emulating Bash nullglob 
  # If argument 1 is not an existing entry
  if [ ! -e "$1" ]
    # argument is a returned pattern
    # then shift it out
    then shift
  fi
  echo $#
}

콤팩트한 정의의 경우:

count_entries(){ [ ! -e "$1" ]&&shift;echo $#;}

유형별 POSIX 호환 파일 카운터:

#!/usr/bin/env sh

count_files()
# Count the file arguments matching the file operator
# Synopsys:
# count_files operator FILE [...]
# Arguments:
# $1: The file operator
#   Allowed values:
#   -a FILE    True if file exists.
#   -b FILE    True if file is block special.
#   -c FILE    True if file is character special.
#   -d FILE    True if file is a directory.
#   -e FILE    True if file exists.
#   -f FILE    True if file exists and is a regular file.
#   -g FILE    True if file is set-group-id.
#   -h FILE    True if file is a symbolic link.
#   -L FILE    True if file is a symbolic link.
#   -k FILE    True if file has its `sticky' bit set.
#   -p FILE    True if file is a named pipe.
#   -r FILE    True if file is readable by you.
#   -s FILE    True if file exists and is not empty.
#   -S FILE    True if file is a socket.
#   -t FD      True if FD is opened on a terminal.
#   -u FILE    True if the file is set-user-id.
#   -w FILE    True if the file is writable by you.
#   -x FILE    True if the file is executable by you.
#   -O FILE    True if the file is effectively owned by you.
#   -G FILE    True if the file is effectively owned by your group.
#   -N FILE    True if the file has been modified since it was last read.
# $@: The files arguments
# Output:
#   The number of matching files
# Return:
#   1: Unknown file operator
{
  operator=$1
  shift
  case $operator in
    -[abcdefghLkprsStuwxOGN])
      for arg; do
        # If file is not of required type
        if ! test "$operator" "$arg"; then
          # Shift it out
          shift
        fi
      done
      echo $#
      ;;
    *)
      printf 'Invalid file operator: %s\n' "$operator" >&2
      return 1
      ;;
  esac
}

count_files "$@"

사용 예:

count_files -f log*.txt
count_files -d datadir*

루프가 없는 대체 디렉터리가 아닌 항목 수:

#!/bin/sh

# Creates strings of as many dots as expanded arguments

# dotted string for entries matching star pattern
star=$(printf '%.0s.' ./*)
# dotted string for entries matching star slash pattern (directories)
star_dir=$(printf '%.0s.' ./*/)
# dotted string for entries matching dot star pattern
dot_star=$(printf '%.0s.' ./.*)
# dotted string for entries matching dot star slash pattern (directories)
dot_star_dir=$(printf '%.0s.' ./.*/)

# Print pattern matches count excluding directories matches
printf 'Files count: %d\n' $((
  ${#star} - ${#star_dir} +
  ${#dot_star} - ${#dot_star_dir}
))

다음은 스크립트에서 사용할 수 있는 일반적인 Bash 함수입니다.

    # @see https://stackoverflow.com/a/11307382/430062
    function countFiles {
        shopt -s nullglob
        logfiles=($1)
        echo ${#logfiles[@]}
    }

    FILES_COUNT=$(countFiles "$file-*")
ls -1 log* | wc -l

즉, 파일을 한 줄에 하나씩 나열한 다음 카운트 라인으로 전환하는 매개 변수를 사용하여 워드 카운트 명령으로 연결합니다.

제가 항상 하는 일은 다음과 같습니다.

lslog* | awk 'END{print NR}'

모든 항목을 카운트하려면 단어 카운트 라인에 파이프만 연결합니다.

ls | wc -l

패턴으로 카운트하려면 먼저 파이프에서 grep로:

ls | grep log | wc -l

언급URL : https://stackoverflow.com/questions/11307257/is-there-a-bash-command-which-counts-files