programing

Bash에서 파일 이름 및 확장자 추출

golfzon 2023. 4. 9. 22:33
반응형

Bash에서 파일 이름 및 확장자 추출

파일명(확장자 없음)과 확장자를 개별적으로 취득하고 싶다.

지금까지 발견한 최고의 솔루션은 다음과 같습니다.

NAME=`echo "$FILE" | cut -d'.' -f1`
EXTENSION=`echo "$FILE" | cut -d'.' -f2`

에 여러 개의 파일 이름이 되어 있으면 않기 은 잘못된 입니다.. if. ,, ,내, 가가가 있다고 칩시다a.b.js , 합니다.a ★★★★★★★★★★★★★★★★★」b.js 「」가 아닌 「」a.b ★★★★★★★★★★★★★★★★★」js.

Python에서는 쉽게 할 수 있습니다.

file, ext = os.path.splitext(path)

하지만 가능하다면 이것 때문에 파이썬 통역사를 고용하고 싶지는 않습니다.

더 좋은 생각 있어?

먼저 경로 없이 파일 이름을 가져옵니다.

filename=$(basename -- "$fullfile")
extension="${filename##*.}"
filename="${filename%.*}"

또는 '.' 대신 경로의 마지막 '/'에 초점을 맞출 수 있습니다. '.'는 파일 확장자를 예측할 수 없는 경우에도 작동합니다.

filename="${fullfile##*/}"

다음의 메뉴얼을 확인해 주세요.

  • 웹의 "3.5.3 셸 파라미터 확장" 섹션
  • "Parameter Expansion" 섹션의 bash manpage에서
~% FILE="example.tar.gz"

~% echo "${FILE%%.*}"
example

~% echo "${FILE%.*}"
example.tar

~% echo "${FILE#*.}"
tar.gz

~% echo "${FILE##*.}"
gz

자세한 내용은 Bash 매뉴얼의 셸 매개 변수 확장을 참조하십시오.

통상, 내선 번호는 이미 알고 있기 때문에, 다음과 같이 사용할 수 있습니다.

basename filename .extension

예를 들어 다음과 같습니다.

basename /path/to/dir/filename.txt .txt

그리고 우리는

filename

POSIX 파라미터 확장의 마법을 사용할 수 있습니다.

bash-3.2$ FILENAME=somefile.tar.gz
bash-3.2$ echo "${FILENAME%%.*}"
somefile
bash-3.2$ echo "${FILENAME%.*}"
somefile.tar

주의사항이 있습니다. 만약 당신의 파일명이./somefile.tar.gzecho ${FILENAME%%.*}.그러면 빈 줄이 생기게 됩니다.

(임시 변수를 사용하여 이 문제를 해결할 수 있습니다.

FULL_FILENAME=$FILENAME
FILENAME=${FULL_FILENAME##*/}
echo ${FILENAME%%.*}

)


자세한 것은, 이쪽을 참조해 주세요.

${variable%pattern}
  Trim the shortest match from the end
${variable##pattern}
  Trim the longest match from the beginning
${variable%%pattern}
  Trim the longest match from the end
${variable#pattern}
  Trim the shortest match from the beginning

파일에 확장자가 없거나 파일 이름이 없는 경우에는 이 기능이 작동하지 않는 것 같습니다.이것은, 빌트인만을 사용하고, 보다 많은 병리 파일명을 처리합니다(전부는 아닙니다).

#!/bin/bash
for fullpath in "$@"
do
    filename="${fullpath##*/}"                      # Strip longest match of */ from start
    dir="${fullpath:0:${#fullpath} - ${#filename}}" # Substring from 0 thru pos of filename
    base="${filename%.[^.]*}"                       # Strip shortest match of . plus at least one non-dot char from end
    ext="${filename:${#base} + 1}"                  # Substring from len of base thru end
    if [[ -z "$base" && -n "$ext" ]]; then          # If we have an extension and no base, it's really the base
        base=".$ext"
        ext=""
    fi

    echo -e "$fullpath:\n\tdir  = \"$dir\"\n\tbase = \"$base\"\n\text  = \"$ext\""
done

테스트 케이스는 다음과 같습니다.

$ basename-and-extension.sh / / home / me / / home / me / file . tar / home / me . tar . gz / home / me / . hidden . tar / home / me / ../:dir = "/"베이스 = "내선번호 = " "/home/me/:
dir = "/home/me/"베이스 = "내선번호 = " "/home/me/file:dir = "/home/me/"기본 = "파일"내선번호 = " "/home/me/file.tar:
dir = "/home/me/"기본 = "파일"ext = "tar"/home/me/file.tar.gz:
dir = "/home/me/"base = "file.tar"ext = "gz"/home/me/.hidden:
dir = "/home/me/"base = ".hidden"내선번호 = " "/home/me/.hidden.tar:
dir = "/home/me/"base = ".hidden"ext = "tar"/home/me/..:dir = "/home/me/"베이스 = ".."내선번호 = " ".:dir = "베이스 = " 입니다.내선번호 = " "
pax> echo a.b.js | sed 's/\.[^.]*$//'
a.b
pax> echo a.b.js | sed 's/^.*\.//'
js

정상적으로 동작하기 때문에, 다음의 조작을 실시할 수 있습니다.

pax> FILE=a.b.js
pax> NAME=$(echo "$FILE" | sed 's/\.[^.]*$//')
pax> EXTENSION=$(echo "$FILE" | sed 's/^.*\.//')
pax> echo $NAME
a.b
pax> echo $EXTENSION
js

참고로 명령어는 다음과 같이 동작합니다.

" " NAMEa로 "."의 수의 가 이어집니다."."도 입력되지 않습니다( 문자에서 을 삭제합니다)."."트릭을 입니다.이것은 기본적으로 regex 속임수를 사용한 비욕적인 대체입니다.

" " EXTENSION는 임의의 하고 그 에 a가 붙습니다."."줄의 시작 부분에 아무것도 없는 문자(즉, 줄의 시작 부분부터 마지막 점까지 포함)를 모두 제거합니다.이것은 디폴트 액션인 대량의 대체입니다.

를 사용할 수 있습니다.

예를 들어:

$ basename foo-bar.tar.gz .tar.gz
foo-bar

을 지정해야 단, "basname"을하고 있는 에는 "basname"을 사용합니다.tar-z는 """가 ..tar.gz.

이 조작은, 다음과 같이 실행할 수 있습니다.

tar -zxvf $1
cd $(basename $1 .tar.gz)

Mellen은 블로그 투고에 코멘트를 쓰고 있다.

하면 Bash도 ${file%.*}하지 않고 이름을 .${file##*.}내선번호만 받을 수 있어요. 것것, that that that.

file="thisfile.txt"
echo "filename: ${file%.*}"
echo "extension: ${file##*.}"

출력:

filename: thisfile
extension: txt

awk ★★★★★★★★★★★★★★★★★」sed또는 심지어perl이 간단한 작업에 사용합니다.바쉬가 os.path.splitext()파라미터 확장만을 사용하는 호환 솔루션.

레퍼런스 실장

의 매뉴얼:

합니다.(root, ext)root + ext == path ext는 비어 있거나 마침표로 시작하며 최대 1개의 마침표를 포함합니다.기본 이름의 선행 마침표는 무시됩니다.splitext('.cshrc')('.cshrc', '').

Python 코드:

root, ext = os.path.splitext(path)

Bash 구현

선행기간의 존중

root="${path%.*}"
ext="${path#"$root"}"

선행 기간 무시

root="${path#.}";root="${path%"$root"}${root%.*}"
ext="${path#"$root"}"

테스트

다음은 Ignorning leading periods 구현 테스트 사례로, 모든 입력에 대한 Python 참조 구현과 일치해야 합니다.

|---------------|-----------|-------|
|path           |root       |ext    |
|---------------|-----------|-------|
|' .txt'        |' '        |'.txt' |
|' .txt.txt'    |' .txt'    |'.txt' |
|' txt'         |' txt'     |''     |
|'*.txt.txt'    |'*.txt'    |'.txt' |
|'.cshrc'       |'.cshrc'   |''     |
|'.txt'         |'.txt'     |''     |
|'?.txt.txt'    |'?.txt'    |'.txt' |
|'\n.txt.txt'   |'\n.txt'   |'.txt' |
|'\t.txt.txt'   |'\t.txt'   |'.txt' |
|'a b.txt.txt'  |'a b.txt'  |'.txt' |
|'a*b.txt.txt'  |'a*b.txt'  |'.txt' |
|'a?b.txt.txt'  |'a?b.txt'  |'.txt' |
|'a\nb.txt.txt' |'a\nb.txt' |'.txt' |
|'a\tb.txt.txt' |'a\tb.txt' |'.txt' |
|'txt'          |'txt'      |''     |
|'txt.pdf'      |'txt'      |'.pdf' |
|'txt.tar.gz'   |'txt.tar'  |'.gz'  |
|'txt.txt'      |'txt'      |'.txt' |
|---------------|-----------|-------|

테스트 결과

모든 테스트 통과.

대체 몇 은 '하다'에 있습니다).awk소프트웨어 패키지의 버전 번호 추출과 같은 고급 사용 사례를 포함합니다.

이들 중 일부는 약간 다른 입력으로 실패할 수 있습니다.따라서 이들 중 일부는 예상되는 입력으로 검증하고 필요에 따라 regex 식을 수정해야 합니다.

f='/path/to/complex/file.1.0.1.tar.gz'

# Filename : 'file.1.0.x.tar.gz'
    echo "$f" | awk -F'/' '{print $NF}'

# Extension (last): 'gz'
    echo "$f" | awk -F'[.]' '{print $NF}'
    
# Extension (all) : '1.0.1.tar.gz'
    echo "$f" | awk '{sub(/[^.]*[.]/, "", $0)} 1'
    
# Extension (last-2): 'tar.gz'
    echo "$f" | awk -F'[.]' '{print $(NF-1)"."$NF}'

# Basename : 'file'
    echo "$f" | awk '{gsub(/.*[/]|[.].*/, "", $0)} 1'

# Basename-extended : 'file.1.0.1.tar'
    echo "$f" | awk '{gsub(/.*[/]|[.]{1}[^.]+$/, "", $0)} 1'

# Path : '/path/to/complex/'
    echo "$f" | awk '{match($0, /.*[/]/, a); print a[0]}'
    # or 
    echo "$f" | grep -Eo '.*[/]'
    
# Folder (containing the file) : 'complex'
    echo "$f" | awk -F'/' '{$1=""; print $(NF-1)}'
    
# Version : '1.0.1'
    # Defined as 'number.number' or 'number.number.number'
    echo "$f" | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?'

    # Version - major : '1'
    echo "$f" | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?' | cut -d. -f1

    # Version - minor : '0'
    echo "$f" | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?' | cut -d. -f2

    # Version - patch : '1'
    echo "$f" | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?' | cut -d. -f3

# All Components : "path to complex file 1 0 1 tar gz"
    echo "$f" | awk -F'[/.]' '{$1=""; print $0}'
    
# Is absolute : True (exit-code : 0)
    # Return true if it is an absolute path (starting with '/' or '~/'
    echo "$f" | grep -q '^[/]\|^~/'
 

모든 사용 사례는 중간 결과에 의존하지 않고 원래 전체 경로를 입력으로 사용합니다.

받아들여진 답변은 일반적경우에는 잘 동작하지만 엣지에서는 실패합니다.즉, 다음과 같습니다.

  • 확장자가 없는 파일 이름(이 응답의 나머지 부분에서는 서픽스라고 부릅니다)의 경우,extension=${filename##*.}는 빈 문자열이 아닌 입력 파일 이름을 반환합니다.
  • extension=${filename##*.}첫 니 does does does does 。.관례에 반하여
    • 으로 .이 서픽스.가 경우는 .
  • filename="${filename%.*}"이 「비어 있다」로 이 됩니다.. 더 이상 하지 않습니다.. 자:.bash_profile ) - 에 반하여) - 상례에 반하여. - 상례에 반하다.

---------

따라서 모든 엣지 케이스를 커버하는 견고한 솔루션의 복잡성에는 함수가 필요합니다.아래의 정의를 참조해 주세요.패스의 모든 컴포넌트를 반환할 수 있습니다.

호출 예:

splitPath '/etc/bash.bashrc' dir fname fnameroot suffix
# -> $dir == '/etc'
# -> $fname == 'bash.bashrc'
# -> $fnameroot == 'bash'
# -> $suffix == '.bashrc'

입력 경로 뒤의 인수는 자유롭게 선택되는 위치 변수 이름에 유의하십시오.
에 오는 , 「 없는 변수」를 합니다._ 변수 )$_ ) 。''를 들어 파일 및 하려면 , 「」를 사용합니다splitPath '/etc/bash.bashrc' _ _ fnameroot extension.


# SYNOPSIS
#   splitPath path varDirname [varBasename [varBasenameRoot [varSuffix]]] 
# DESCRIPTION
#   Splits the specified input path into its components and returns them by assigning
#   them to variables with the specified *names*.
#   Specify '' or throw-away variable _ to skip earlier variables, if necessary.
#   The filename suffix, if any, always starts with '.' - only the *last*
#   '.'-prefixed token is reported as the suffix.
#   As with `dirname`, varDirname will report '.' (current dir) for input paths
#   that are mere filenames, and '/' for the root dir.
#   As with `dirname` and `basename`, a trailing '/' in the input path is ignored.
#   A '.' as the very first char. of a filename is NOT considered the beginning
#   of a filename suffix.
# EXAMPLE
#   splitPath '/home/jdoe/readme.txt' parentpath fname fnameroot suffix
#   echo "$parentpath" # -> '/home/jdoe'
#   echo "$fname" # -> 'readme.txt'
#   echo "$fnameroot" # -> 'readme'
#   echo "$suffix" # -> '.txt'
#   ---
#   splitPath '/home/jdoe/readme.txt' _ _ fnameroot
#   echo "$fnameroot" # -> 'readme'  
splitPath() {
  local _sp_dirname= _sp_basename= _sp_basename_root= _sp_suffix=
    # simple argument validation
  (( $# >= 2 )) || { echo "$FUNCNAME: ERROR: Specify an input path and at least 1 output variable name." >&2; exit 2; }
    # extract dirname (parent path) and basename (filename)
  _sp_dirname=$(dirname "$1")
  _sp_basename=$(basename "$1")
    # determine suffix, if any
  _sp_suffix=$([[ $_sp_basename = *.* ]] && printf %s ".${_sp_basename##*.}" || printf '')
    # determine basename root (filemane w/o suffix)
  if [[ "$_sp_basename" == "$_sp_suffix" ]]; then # does filename start with '.'?
      _sp_basename_root=$_sp_basename
      _sp_suffix=''
  else # strip suffix from filename
    _sp_basename_root=${_sp_basename%$_sp_suffix}
  fi
  # assign to output vars.
  [[ -n $2 ]] && printf -v "$2" "$_sp_dirname"
  [[ -n $3 ]] && printf -v "$3" "$_sp_basename"
  [[ -n $4 ]] && printf -v "$4" "$_sp_basename_root"
  [[ -n $5 ]] && printf -v "$5" "$_sp_suffix"
  return 0
}

test_paths=(
  '/etc/bash.bashrc'
  '/usr/bin/grep'
  '/Users/jdoe/.bash_profile'
  '/Library/Application Support/'
  'readme.new.txt'
)

for p in "${test_paths[@]}"; do
  echo ----- "$p"
  parentpath= fname= fnameroot= suffix=
  splitPath "$p" parentpath fname fnameroot suffix
  for n in parentpath fname fnameroot suffix; do
    echo "$n=${!n}"
  done
done

기능을 실행하는 테스트 코드:

test_paths=(
  '/etc/bash.bashrc'
  '/usr/bin/grep'
  '/Users/jdoe/.bash_profile'
  '/Library/Application Support/'
  'readme.new.txt'
)

for p in "${test_paths[@]}"; do
  echo ----- "$p"
  parentpath= fname= fnameroot= suffix=
  splitPath "$p" parentpath fname fnameroot suffix
  for n in parentpath fname fnameroot suffix; do
    echo "$n=${!n}"
  done
done

예상 출력 - 에지 대소문자를 기록합니다.

  • 접미사가 없는 파일 이름
  • 「」으로 하는 ..(서픽스의 시작은 고려되지 않음)
  • 「」로 / (비밀(이행)/무시됩니다).
  • (「」).됩니다).
  • 「」보다 큰 ..token(서픽스로 간주됩니다.
----- /etc/bash.bashrc
parentpath=/etc
fname=bash.bashrc
fnameroot=bash
suffix=.bashrc
----- /usr/bin/grep
parentpath=/usr/bin
fname=grep
fnameroot=grep
suffix=
----- /Users/jdoe/.bash_profile
parentpath=/Users/jdoe
fname=.bash_profile
fnameroot=.bash_profile
suffix=
----- /Library/Application Support/
parentpath=/Library
fname=Application Support
fnameroot=Application Support
suffix=
----- readme.new.txt
parentpath=.
fname=readme.new.txt
fnameroot=readme.new
suffix=.txt

명령어를 사용하여 마지막 2개의 내선번호를 삭제할 수 있습니다(".tar.gz" : 디폴트) :

$ echo "foo.tar.gz" | cut -d'.' --complement -f2-
foo

Clayton Hughes가 코멘트에서 지적한 바와 같이, 이는 질문의 실제 예에 적용되지 않을 것이다.그래서 대안으로 나는 다음을 사용할 것을 제안한다.sed다음과 같은 확장 정규 표현을 사용합니다.

$ echo "mpc-1.0.1.tar.gz" | sed -r 's/\.[[:alnum:]]+\.[[:alnum:]]+$//'
mpc-1.0.1

이 기능은 마지막 두 개의 영숫자 확장자를 무조건 삭제함으로써 작동합니다.

[안데르스 린달의 코멘트로 다시 업데이트]

가장 작고 심플한 솔루션(한 줄로 표시)은 다음과 같습니다.

$ file=/blaabla/bla/blah/foo.txt
echo $(basename ${file%.*}) # foo

파일 이름만 필요한 경우 다음을 시도해 보십시오.

FULLPATH=/usr/share/X11/xorg.conf.d/50-synaptics.conf

# Remove all the prefix until the "/" character
FILENAME=${FULLPATH##*/}

# Remove all the prefix until the "." character
FILEEXTENSION=${FILENAME##*.}

# Remove a suffix, in our case, the filename. This will return the name of the directory that contains this file.
BASEDIRECTORY=${FULLPATH%$FILENAME}

echo "path = $FULLPATH"
echo "file name = $FILENAME"
echo "file extension = $FILEEXTENSION"
echo "base directory = $BASEDIRECTORY"

이것으로 =D입니다.

및 수 .이러한 필드에는, 「이러한 필드」가 추가되어 .-필드 번호에 접속합니다.

NAME=`basename "$FILE"`
EXTENSION=`echo "$NAME" | cut -d'.' -f2-`

FILE이 '''FILE''이면eth0.pcap.gz은, EXTENSION이 .pcap.gz

같은 논리를 사용하여 다음과 같이 잘라낸 '-'를 사용하여 파일 이름을 가져올 수도 있습니다.

NAME=`basename "$FILE" | cut -d'.' -f-1`

이 기능은 확장자가 없는 파일 이름에서도 사용할 수 있습니다.

나한테 효과가 있었던 건 이것뿐이었어

path='folder/other_folder/file.js'

base=${path##*/}
echo ${base%.*}

>> file

은 문자열 할 수 만, 도 「」를 설정할 가 있습니다.base리리확확확확확확

$ F = "text file.test.txt"  
$ echo ${F/*./}  
txt  

이것은 파일명의 여러 점 및 공간을 지원하지만 확장자가 없는 경우 파일 이름 자체를 반환합니다.다만, 간단하게 확인할 수 있습니다.파일명과 확장자가 같은지 테스트하기만 하면 됩니다.

당연히 이 방법은 .tar.gz 파일에는 적용되지 않습니다.그러나 그것은 2단계 프로세스로 처리될 수 있다.내선번호가 gz일 경우 tar 내선번호도 있는지 다시 확인합니다.

매직 파일 인식

이 Stack Overflow 질문에 대한 좋은 답변 외에도 다음과 같이 추가하고자 합니다.

Linux 및 기타 unixen에는 다음과 같은 마법 명령어가 있습니다.file파일의 첫 번째 바이트를 분석하여 파일 형식 검출을 수행합니다.이 도구는 매우 오래된 도구이며, 인쇄 서버에 초기 사용되었습니다(생성되지 않은 경우...).★★★★★★★★★★★★★★★★★★★★★★★」

file myfile.txt
myfile.txt: UTF-8 Unicode text

file -b --mime-type myfile.txt
text/plain

표준 확장은 다음에서 찾을 수 있습니다./etc/mime.types(Debian GNU/Linux 데스크톱에서).man file ★★★★★★★★★★★★★★★★★」man mime.types를 인스톨 할 필요가 있는 경우가 있습니다.file와 '''입니다.mime-support★★★★★★★★★★★★★★★★★★:

grep $( file -b --mime-type myfile.txt ) </etc/mime.types
text/plain      asc txt text pot brf srt

확장을 결정하기 위한 bash 함수를 생성할 수 있습니다.약간의 샘플(완벽하지 않은)이 있습니다.

file2ext() {
    local _mimetype=$(file -Lb --mime-type "$1") _line _basemimetype
    case ${_mimetype##*[/.-]} in
        gzip | bzip2 | xz | z )
            _mimetype=${_mimetype##*[/.-]}
            _mimetype=${_mimetype//ip}
            _basemimetype=$(file -zLb --mime-type "$1")
            ;;
        stream )
            _mimetype=($(file -Lb "$1"))
            [ "${_mimetype[1]}" = "compressed" ] &&
                _basemimetype=$(file -b --mime-type - < <(
                        ${_mimetype,,} -d <"$1")) ||
                _basemimetype=${_mimetype,,}
            _mimetype=${_mimetype,,}
            ;;
        executable )  _mimetype='' _basemimetype='' ;;
        dosexec )     _mimetype='' _basemimetype='exe' ;;
        shellscript ) _mimetype='' _basemimetype='sh' ;;
        * )
            _basemimetype=$_mimetype
            _mimetype=''
            ;;
    esac
    while read -a _line ;do
        if [ "$_line" == "$_basemimetype" ] ;then
            [ "$_line[1]" ] &&
                _basemimetype=${_line[1]} ||
                _basemimetype=${_basemimetype##*[/.-]}
            break
        fi
        done </etc/mime.types
    case ${_basemimetype##*[/.-]} in
        executable ) _basemimetype='' ;;
        shellscript ) _basemimetype='sh' ;;
        dosexec ) _basemimetype='exe' ;;
        * ) ;;
    esac
    [ "$_mimetype" ] && [ "$_basemimetype" != "$_mimetype" ] &&
      printf ${2+-v} $2 "%s.%s" ${_basemimetype##*[/.-]} ${_mimetype##*[/.-]} ||
      printf ${2+-v} $2 "%s" ${_basemimetype##*[/.-]}
}

이 함수는 나중에 사용할 수 있는 Bash 변수를 설정할 수 있습니다.

(이것은 @Petesh의 정답에서 영감을 얻은 것입니다).

filename=$(basename "$fullfile")
filename="${filename%.*}"
file2ext "$fullfile" extension

echo "$fullfile -> $filename . $extension"

가 제대로 했다면, 는 확장자가 개인 풀입니다.를 들어, 확장자가 여러 개인 파일입니다.stuff.tar.gz.

이것으로 충분합니다.

fullfile="stuff.tar.gz"
fileExt=${fullfile#*.}
fileName=${fullfile%*.$fileExt}

이것으로 알 수 있습니다.stuff 및 ""로 합니다..tar.gz0.0 의 확장자임의 동작합니다.를 안고 있는 이 되기를

'만들기'를 사용하세요.${parameter%word}

고객님의 경우:

${FILE%.*}

테스트하는 경우는, 다음의 조작을 실시해, 확장자를 삭제하기만 하면 됩니다.

FILE=abc.xyz; echo ${FILE%.*};
FILE=123.abc.xyz; echo ${FILE%.*};
FILE=abc; echo ${FILE%.*};

다음 스크립트를 사용합니다.

$ echo "foo.tar.gz"|rev|cut -d"." -f3-|rev
foo

fish에서 파일 이름 및 확장자를 추출하는 방법:

function split-filename-extension --description "Prints the filename and extension"
  for file in $argv
    if test -f $file
      set --local extension (echo $file | awk -F. '{print $NF}')
      set --local filename (basename $file .$extension)
      echo "$filename $extension"
    else
      echo "$file is not a valid file"
    end
  end
end

주의: 마지막 점으로 분할됩니다.이것은 점이 있는 파일 이름에는 적합하지만, 점이 있는 확장자에는 적합하지 않습니다.아래의 예를 참조해 주세요.

사용방법:

$ split-filename-extension foo-0.4.2.zip bar.tar.gz
foo-0.4.2 zip  # Looks good!
bar.tar gz  # Careful, you probably want .tar.gz as the extension.

더 좋은 방법이 있을 거야제 답변은 자유롭게 수정하여 개선해 주십시오.


취급하는 내선번호가 한정되어 있어 모두 알고 있는 경우는, 다음과 같이 시험해 주세요.

switch $file
  case *.tar
    echo (basename $file .tar) tar
  case *.tar.bz2
    echo (basename $file .tar.bz2) tar.bz2
  case *.tar.gz
    echo (basename $file .tar.gz) tar.gz
  # and so on
end

이 예에서는 첫 번째 예로는 주의사항이 없지만 모든 케이스를 처리해야 합니다.따라서 예상되는 내선번호 수에 따라서는 번거로울 수 있습니다.

여기 AWK 코드입니다.그것은 좀 더 간단하게 할 수 있다.하지만 나는 AWK를 잘하지 못한다.

filename$ ls
abc.a.txt  a.b.c.txt  pp-kk.txt
filename$ find . -type f | awk -F/ '{print $2}' | rev | awk -F"." '{$1="";print}' | rev | awk 'gsub(" ",".") ,sub(".$", "")'
abc.a
a.b.c
pp-kk
filename$ find . -type f | awk -F/ '{print $2}' | awk -F"." '{print $NF}'
txt
txt
txt

Petesh answer에서 작성하면 파일 이름만 필요할 경우 경로와 확장자를 한 줄로 삭제할 수 있습니다.

filename=$(basename ${fullname%.*})

regexbash regex를 하지 않았습니다.
다음은 경로를 다음과 같이 분할하는 순수 bash 솔루션입니다.

  • 디렉토리 경로(후행 포함)/
    의 「」를 ./
  • (마지막) 도트 확장자를 제외한 파일 이름
  • 선두가 있는 (마지막) 도트 확장자.

이 암호는 가능한 모든 사건을 처리하도록 되어 있습니다. 시도해 보세요.

#!/bin/bash

for path; do

####### the relevant part ######

[[ $path =~ ^(\.{1,2}|.*/\.{0,2})$|^(.*/)([^/]+)(\.[^/]*)$|^(.*/)(.+)$|^(.+)(\..*)$|^(.+)$ ]]

dirpath=${BASH_REMATCH[1]}${BASH_REMATCH[2]}${BASH_REMATCH[5]}
filename=${BASH_REMATCH[3]}${BASH_REMATCH[6]}${BASH_REMATCH[7]}${BASH_REMATCH[9]}
filext=${BASH_REMATCH[4]}${BASH_REMATCH[8]}

# dirpath should be non-null
[[ $dirpath ]] || dirpath='.'

################################

printf '%s=%q\n' \
    path     "$path" \
    dirpath  "$dirpath" \
    filename "$filename" \
    filext   "$filext"

done

어떻게 작동합니까?

1개의 표현식1'로 구분됨)만할 수 .|down을 할 수 .에 의해, 「」에 되어 있는 같은의 모든 캡처 그룹(를 들면,패스에 을할 수 .BASH_REMATCH기껏해야 1개는 비고정적이기 때문입니다.

다음은 광범위하지는 않지만 포괄적인 예제의 결과입니다.
+--------------------------------------------------------+
| input             dirpath        filename       filext |
+--------------------------------------------------------+
''                  .              ''             ''
.                   .              ''             ''
..                  ..             ''             ''
...                 .              ..             .
.file               .              .file          ''
.file.              .              .file          .
.file..             .              .file.         .
.file.Z             .              .file          .Z
.file.sh.Z          .              .file.sh       .Z
file                .              file           ''
file.               .              file           .
file..              .              file.          .
file.Z              .              file           .Z
file.sh.Z           .              file.sh        .Z
dir/                dir/           ''             ''
dir/.               dir/.          ''             ''
dir/...             dir/           ..             .
dir/.file           dir/           .file          ''
dir/.file.          dir/           .file          .
dir/.file..         dir/           .file.         .
dir/.file.Z         dir/           .file          .Z
dir/.file.x.Z       dir/           .file.x        .Z
dir/file            dir/           file           ''
dir/file.           dir/           file           .
dir/file..          dir/           file.          .
dir/file.Z          dir/           file           .Z
dir/file.x.Z        dir/           file.x         .Z
dir./.              dir./.         ''             ''
dir./...            dir./          ..             .
dir./.file          dir./          .file          ''
dir./.file.         dir./          .file          .
dir./.file..        dir./          .file.         .
dir./.file.Z        dir./          .file          .Z
dir./.file.sh.Z     dir./          .file.sh       .Z
dir./file           dir./          file           ''
dir./file.          dir./          file           .
dir./file..         dir./          file.          .
dir./file.Z         dir./          file           .Z
dir./file.x.Z       dir./          file.x         .Z
dir//               dir//          ''             ''
dir//.              dir//.         ''             ''
dir//...            dir//          ..             .
dir//.file          dir//          .file          ''
dir//.file.         dir//          .file          .
dir//.file..        dir//          .file.         .
dir//.file.Z        dir//          .file          .Z
dir//.file.x.Z      dir//          .file.x        .Z
dir//file           dir//          file           ''
dir//file.          dir//          file           .
dir//file..         dir//          file.          .
dir//file.Z         dir//          file           .Z
dir//file.x.Z       dir//          file.x         .Z
dir.//.             dir.//.        ''             ''
dir.//...           dir.//         ..             .
dir.//.file         dir.//         .file          ''
dir.//.file.        dir.//         .file          .
dir.//.file..       dir.//         .file.         .
dir.//.file.Z       dir.//         .file          .Z
dir.//.file.x.Z     dir.//         .file.x        .Z
dir.//file          dir.//         file           ''
dir.//file.         dir.//         file           .
dir.//file..        dir.//         file.          .
dir.//file.Z        dir.//         file           .Z
dir.//file.x.Z      dir.//         file.x         .Z
/                   /              ''             ''
/.                  /.             ''             ''
/..                 /..            ''             ''
/...                /              ..             .
/.file              /              .file          ''
/.file.             /              .file          .
/.file..            /              .file.         .
/.file.Z            /              .file          .Z
/.file.sh.Z         /              .file.sh       .Z
/file               /              file           ''
/file.              /              file           .
/file..             /              file.          .
/file.Z             /              file           .Z
/file.sh.Z          /              file.sh        .Z
/dir/               /dir/          ''             ''
/dir/.              /dir/.         ''             ''
/dir/...            /dir/          ..             .
/dir/.file          /dir/          .file          ''
/dir/.file.         /dir/          .file          .
/dir/.file..        /dir/          .file.         .
/dir/.file.Z        /dir/          .file          .Z
/dir/.file.x.Z      /dir/          .file.x        .Z
/dir/file           /dir/          file           ''
/dir/file.          /dir/          file           .
/dir/file..         /dir/          file.          .
/dir/file.Z         /dir/          file           .Z
/dir/file.x.Z       /dir/          file.x         .Z
/dir./.             /dir./.        ''             ''
/dir./...           /dir./         ..             .
/dir./.file         /dir./         .file          ''
/dir./.file.        /dir./         .file          .
/dir./.file..       /dir./         .file.         .
/dir./.file.Z       /dir./         .file          .Z
/dir./.file.sh.Z    /dir./         .file.sh       .Z
/dir./file          /dir./         file           ''
/dir./file.         /dir./         file           .
/dir./file..        /dir./         file.          .
/dir./file.Z        /dir./         file           .Z
/dir./file.x.Z      /dir./         file.x         .Z
/dir//              /dir//         ''             ''
/dir//.             /dir//.        ''             ''
/dir//...           /dir//         ..             .
/dir//.file         /dir//         .file          ''
/dir//.file.        /dir//         .file          .
/dir//.file..       /dir//         .file.         .
/dir//.file.Z       /dir//         .file          .Z
/dir//.file.x.Z     /dir//         .file.x        .Z
/dir//file          /dir//         file           ''
/dir//file.         /dir//         file           .
/dir//file..        /dir//         file.          .
/dir//file.Z        /dir//         file           .Z
/dir//file.x.Z      /dir//         file.x         .Z
/dir.//.            /dir.//.       ''             ''
/dir.//...          /dir.//        ..             .
/dir.//.file        /dir.//        .file          ''
/dir.//.file.       /dir.//        .file          .
/dir.//.file..      /dir.//        .file.         .
/dir.//.file.Z      /dir.//        .file          .Z
/dir.//.file.x.Z    /dir.//        .file.x        .Z
/dir.//file         /dir.//        file           ''
/dir.//file.        /dir.//        file           .
/dir.//file..       /dir.//        file.          .
/dir.//file.Z       /dir.//        file           .Z
/dir.//file.x.Z     /dir.//        file.x         .Z
//                  //             ''             ''
//.                 //.            ''             ''
//..                //..           ''             ''
//...               //             ..             .
//.file             //             .file          ''
//.file.            //             .file          .
//.file..           //             .file.         .
//.file.Z           //             .file          .Z
//.file.sh.Z        //             .file.sh       .Z
//file              //             file           ''
//file.             //             file           .
//file..            //             file.          .
//file.Z            //             file           .Z
//file.sh.Z         //             file.sh        .Z
//dir/              //dir/         ''             ''
//dir/.             //dir/.        ''             ''
//dir/...           //dir/         ..             .
//dir/.file         //dir/         .file          ''
//dir/.file.        //dir/         .file          .
//dir/.file..       //dir/         .file.         .
//dir/.file.Z       //dir/         .file          .Z
//dir/.file.x.Z     //dir/         .file.x        .Z
//dir/file          //dir/         file           ''
//dir/file.         //dir/         file           .
//dir/file..        //dir/         file.          .
//dir/file.Z        //dir/         file           .Z
//dir/file.x.Z      //dir/         file.x         .Z
//dir./.            //dir./.       ''             ''
//dir./...          //dir./        ..             .
//dir./.file        //dir./        .file          ''
//dir./.file.       //dir./        .file          .
//dir./.file..      //dir./        .file.         .
//dir./.file.Z      //dir./        .file          .Z
//dir./.file.sh.Z   //dir./        .file.sh       .Z
//dir./file         //dir./        file           ''
//dir./file.        //dir./        file           .
//dir./file..       //dir./        file.          .
//dir./file.Z       //dir./        file           .Z
//dir./file.x.Z     //dir./        file.x         .Z
//dir//             //dir//        ''             ''
//dir//.            //dir//.       ''             ''
//dir//...          //dir//        ..             .
//dir//.file        //dir//        .file          ''
//dir//.file.       //dir//        .file          .
//dir//.file..      //dir//        .file.         .
//dir//.file.Z      //dir//        .file          .Z
//dir//.file.x.Z    //dir//        .file.x        .Z
//dir//file         //dir//        file           ''
//dir//file.        //dir//        file           .
//dir//file..       //dir//        file.          .
//dir//file.Z       //dir//        file           .Z
//dir//file.x.Z     //dir//        file.x         .Z
//dir.//.           //dir.//.      ''             ''
//dir.//...         //dir.//       ..             .
//dir.//.file       //dir.//       .file          ''
//dir.//.file.      //dir.//       .file          .
//dir.//.file..     //dir.//       .file.         .
//dir.//.file.Z     //dir.//       .file          .Z
//dir.//.file.x.Z   //dir.//       .file.x        .Z
//dir.//file        //dir.//       file           ''
//dir.//file.       //dir.//       file           .
//dir.//file..      //dir.//       file.          .
//dir.//file.Z      //dir.//       file           .Z
//dir.//file.x.Z    //dir.//       file.x         .Z

, 행동도 다르다.basename ★★★★★★★★★★★★★★★★★」dirname를 들어,예를들면basename dir/ 력 outputsdir정규식을 사용하다일일도 입니다.. ★★★★★★★★★★★★★★★★★」..이치노

만, 한 POSIX 쉘256자 내의 콜을(POSIX 2forloop느립니다.loop)는 60배 느립니다.

비고: 다음을 포함하는 경로를 테스트할 필요는 없습니다.\n모든 문자가 bash의 regex 엔진에 의해 동일하게 처리되기 때문에 다른 악명 높은 문자도 마찬가지입니다.현재의 논리를 깨뜨릴 수 있는 유일한 문자는 다음과 같습니다./ ★★★★★★★★★★★★★★★★★」., 현재 예기치 않은 방법으로 혼재 또는 곱셈됩니다.제가 처음 답변을 올렸을 때 수정해야 할 국경 케이스를 발견했습니다.정규가 100% 방탄이라고는 할 수 없지만 지금은 상당히 견고할 것입니다.


이와는 별도로 동일한 출력을 제공하는 POSIX 쉘 솔루션을 다음에 나타냅니다.

#!/bin/sh

for path; do

####### the relevant part ######

fullname=${path##*/}

case $fullname in
. | ..)
    dirpath="$path"
    filename=''
    filext=''
    ;;
*)
    dirpath=${path%"$fullname"}
    dirpath=${dirpath:-.}       # dirpath should be non-null
    filename=${fullname#.}
    filename="${fullname%"$filename"}${filename%.*}"
    filext=${fullname#"$filename"}
    ;;
esac

################################

printf '%s=%s\n' \
    path     "$path" \
    dirpath  "$dirpath" \
    filename "$filename" \
    filext   "$filext"

done

포스트스크립트:위의 코드에 의해 제시된 결과에 동의하지 않는 사람이 있을 수 있는 몇 가지 포인트가 있습니다.

  • 닷파일의 특수한 경우:그 이유는 닷파일이 UNIX 개념이기 때문입니다.

  • ★★★★★★★★★★★★★★★★★★★★의 특례. ★★★★★★★★★★★★★★★★★」..IMHO는 이들을 디렉토리로 취급하는 것은 당연하지만 대부분의 라이브러리는 그렇게 하지 않고 사용자가 결과를 후처리하도록 강요합니다.

  • 이중 내선번호는 지원되지 않습니다.확장자를 하기 위해 확장자는 UNIX에서 입니다. 아카이브를 할 수 . 타르my_tarred_files괜찮아요, 그럼 이제 되겠네요.tar xf my_tarred_files문제없이.

주로 @mklement0의 우수성과 랜덤하고 유용한 배시즘으로 가득 찬 것 외에 이 질문/기타 질문/그 망할 인터넷에 대한 다른 답변에 기초하고 있습니다.이 모든 것을 조금 더 이해하기 쉽고 재사용 가능한 기능으로 정리했습니다..bash_profile보다 견고한 버전이어야 할 것(제 생각에)에 대응하고 있습니다.dirname/basename/ 대체 무슨..

function path { SAVEIFS=$IFS; IFS=""   # stash IFS for safe-keeping, etc.
    [[ $# != 2 ]] && echo "usage: path <path> <dir|name|fullname|ext>" && return    # demand 2 arguments
    [[ $1 =~ ^(.*/)?(.+)?$ ]] && {     # regex parse the path
        dir=${BASH_REMATCH[1]}
        file=${BASH_REMATCH[2]}
        ext=$([[ $file = *.* ]] && printf %s ${file##*.} || printf '')
        # edge cases for extensionless files and files like ".nesh_profile.coffee"
        [[ $file == $ext ]] && fnr=$file && ext='' || fnr=${file:0:$((${#file}-${#ext}))}
        case "$2" in
             dir) echo      "${dir%/*}"; ;;
            name) echo      "${fnr%.*}"; ;;
        fullname) echo "${fnr%.*}.$ext"; ;;
             ext) echo           "$ext"; ;;
        esac
    }
    IFS=$SAVEIFS
}     

사용 예...

SOMEPATH=/path/to.some/.random\ file.gzip
path $SOMEPATH dir        # /path/to.some
path $SOMEPATH name       # .random file
path $SOMEPATH ext        # gzip
path $SOMEPATH fullname   # .random file.gzip                     
path gobbledygook         # usage: -bash <path> <dir|name|fullname|ext>

간단한 답변:

POSIX 변수 응답을 확장하려면 더 흥미로운 패턴을 수행할 수 있습니다.여기서 설명하는 경우는, 간단하게 다음과 같이 할 수 있습니다.

tar -zxvf $1
cd ${1%.tar.*}

그러면 .tar의 마지막 발생이 차단됩니다.<뭔가>.

일반적으로 .<something>의 마지막 항목을 삭제하는 경우.<something-something> 그럼

${1.*.*}

정상적으로 동작합니다.

위의 답변 링크는 비활성 상태입니다.다음은 Bash에서 TLDP에서 직접 실행할 수 있는 문자열 조작에 대한 설명입니다.

빈 내선번호도 허용하고 싶은 경우, 이것이 가장 짧은 방법입니다.

echo 'hello.txt' | sed -r 's/.+\.(.+)|.*/\1/' # EXTENSION
echo 'hello.txt' | sed -r 's/(.+)\..+|(.*)/\1\2/' # FILENAME

첫 번째 줄 설명:PATH와 일치합니다.EXT 또는 모든 것을 EXT로 바꿉니다.ANY가 일치하는 경우 ext 그룹은 캡처되지 않습니다.

IMHO는 셸 파라미터 확장을 사용하여 이미 최적의 솔루션이 제공되었으며, 현시점에서는 최고의 평가를 받고 있습니다.

그러나 이 명령어는 dumbs 명령어만을 사용하는 것으로, 효율적이지 않고, 진지하게 사용하는 것은 없습니다.

FILENAME=$(echo $FILE | cut -d . -f 1-$(printf $FILE | tr . '\n' | wc -l))
EXTENSION=$(echo $FILE | tr . '\n' | tail -1)

장난삼아 추가 :-)

다음은 Bash 스크립트를 작성할 때 파일 이름과 확장자를 검색하여 이름이 대소문자와 충돌할 때 이름을 고유하게 만들었던 알고리즘입니다.

#! /bin/bash 

#
# Finds 
# -- name and extension pairs
# -- null extension when there isn't an extension.
# -- Finds name of a hidden file without an extension
# 

declare -a fileNames=(
  '.Montreal' 
  '.Rome.txt' 
  'Loundon.txt' 
  'Paris' 
  'San Diego.txt'
  'San Francisco' 
  )

echo "Script ${0} finding name and extension pairs."
echo 

for theFileName in "${fileNames[@]}"
do
     echo "theFileName=${theFileName}"  

     # Get the proposed name by chopping off the extension
     name="${theFileName%.*}"

     # get extension.  Set to null when there isn't an extension
     # Thanks to mklement0 in a comment above.
     extension=$([[ "$theFileName" == *.* ]] && echo ".${theFileName##*.}" || echo '')

     # a hidden file without extenson?
     if [ "${theFileName}" = "${extension}" ] ; then
         # hidden file without extension.  Fixup.
         name=${theFileName}
         extension=""
     fi

     echo "  name=${name}"
     echo "  extension=${extension}"
done 

테스트 실행

$ config/Name\&Extension.bash 
Script config/Name&Extension.bash finding name and extension pairs.

theFileName=.Montreal
  name=.Montreal
  extension=
theFileName=.Rome.txt
  name=.Rome
  extension=.txt
theFileName=Loundon.txt
  name=Loundon
  extension=.txt
theFileName=Paris
  name=Paris
  extension=
theFileName=San Diego.txt
  name=San Diego
  extension=.txt
theFileName=San Francisco
  name=San Francisco
  extension=
$ 

참고: 완전한 번역 프로그램 및 기타 테스트 케이스는 https://www.dropbox.com/s/4c6m0f2e28a1vxf/avoid-clashes-code.zip?dl=0에서 확인할 수 있습니다.

언급URL : https://stackoverflow.com/questions/965053/extract-filename-and-extension-in-bash

반응형