쉘 스크립트에서 파일 이름의 확장자를 어떻게 제거합니까?


144

다음 코드의 문제점은 무엇입니까?

name='$filename | cut -f1 -d'.''

그대로 리터럴 string을 얻지 $filename | cut -f1 -d'.'만 따옴표를 제거하면 아무것도 얻지 못합니다. 한편, 타이핑

"test.exe" | cut -f1 -d'.'

쉘에서 내가 원하는 출력을 제공합니다 test. 나는 이미 $filename올바른 가치가 부여되었음을 알고 있다. 내가하고 싶은 것은 확장자가없는 파일 이름을 변수에 할당하는 것입니다.


6
basename $filename .exe같은 일을 할 것입니다. 그것은 당신이 항상 어떤 확장을 제거하고 싶은지 알고 있다고 가정합니다.
mpe

6
@mpe, 당신은 의미 basename "$filename" .exe합니다. 그렇지 않으면 공백이있는 파일 이름은 나쁜 소식입니다.
Charles Duffy

답변:


113

스크립트 / 명령에서 명령을 실행 하려면 명령 대체 구문을 사용해야합니다 $(command).

그래서 당신의 라인은

name=$(echo "$filename" | cut -f 1 -d '.')

코드 설명 :

  1. echo변수 값을 가져 와서 $filename표준 출력으로 보냅니다.
  2. 그런 다음 출력을 잡고 cut명령에 파이프합니다.
  3. cut을 사용합니다. 문자열을 세그먼트로 자르기위한 분리 문자 (구분 자로도 알려짐)로 -f출력에 포함 할 세그먼트를 선택합니다.
  4. 그런 다음 $()명령 대체는 출력을 가져 와서 값을 반환합니다.
  5. 반환 된 값은 변수 이름에 할당됩니다 name

이것은 변수의 일부를 첫 번째 기간까지 제공합니다 ..

$ filename=hello.world
$ echo "$filename" | cut -f 1 -d '.'
hello
$ filename=hello.hello.hello
$ echo "$filename" | cut -f 1 -d '.'
hello
$ filename=hello
$ echo "$filename" | cut -f 1 -d '.'
hello

감사. echo 명령을 사용해야한다는 것도 알았습니다. name =echo $filename | cut -f1 -d'.'
mimicocotopus 4

17
백틱은 POSIX에서 더 이상 사용되지 않으며 $()선호됩니다.
jordanm

3
몇 문자를 얻기위한 포크와 파이핑은 상상할 수있는 최악의 솔루션에 관한 것입니다.
Jens

39
이 답변의 문제는 입력 문자열이 하나의 점 ... @chepner 아래에있는 더 나은 솔루션 ... 이름 = $가 가정이다 {파일 이름 %를 *.}
스콧 Stensland

4
이 답변은 초보자의 특징이며 확산되어서는 안됩니다. chepner의 대답에 의해 설명 된대로 내장 메커니즘을 사용
neric

258

매개 변수 확장을 사용할 수도 있습니다.

$ filename=foo.txt
$ echo "${filename%.*}"
foo

6
명령에 대한 설명은 다음과 같습니다. gnu.org/software/bash/manual/html_node/…
Carlos Robles

1
그리고 여기에 사용하려고했습니다 echo -n "This.File.Has.Periods.In.It.txt" | awk -F. '{$NF=""; print $0}' | tr ' ' '.' | rev | cut -c 2- | rev. 감사.
user208145

1
?와 같은 여러 확장명을 가진 파일에서 작동합니까 image.png.gz?
Hawker65

11
%.*마지막 확장 만 제거합니다. 모든 확장 을 제거 하려면을 사용하십시오 %%.*.
chepner

1
이것은 허용 된 답변보다 더 잘 작동하는 것 같습니다. 파일에 점이 두 개 이상인 경우 마지막 확장자 만 제거하는 반면 cut은 첫 번째 점 뒤의 모든 항목을 제거합니다.
데일 앤더슨


20

파일 이름에 점 (확장자 이외의 점)이 포함 된 경우 다음을 사용하십시오.

echo $filename | rev | cut -f 2- -d '.' | rev

1
나는 중간 rev를 잊어 버렸지 만 일단 그것을 보았을 때, 이것은 훌륭했습니다!
최고 Pooba

파일 이름에 점이 없을 때마다 빈 문자열을 반환하도록에 -s지정된 옵션을 사용하는 것이 훨씬 좋습니다 cut.
Hibou57

1
내 의견으로는 받아 들일만한 대답이어야합니다. 점으로 점이있는 경로, 점으로 시작하는 숨겨진 파일 또는 여러 확장명이있는 파일로 작동하기 때문입니다.
팀 크리프

20
file1=/tmp/main.one.two.sh
t=$(basename "$file1")                        # output is main.one.two.sh
name=$(echo "$file1" | sed -e 's/\.[^.]*$//') # output is /tmp/main.one.two
name=$(echo "$t" | sed -e 's/\.[^.]*$//')     # output is main.one.two

원하는 것을 사용하십시오. 여기서 나는 마지막 .(점) 뒤에 텍스트가 확장자 라고 가정합니다 .


6
#!/bin/bash
file=/tmp/foo.bar.gz
echo $file ${file%.*}

출력 :

/tmp/foo.bar.gz /tmp/foo.bar

마지막 확장명 만 제거됩니다.


3

내 추천은 사용하는 것 basename입니다.
우분투에서는 기본적으로 시각적으로 간단한 코드이며 대부분의 경우를 처리합니다.

다음은 공백과 멀티 도트 / 하위 확장을 다루는 몇 가지 하위 사례입니다.

pathfile="../space fld/space -file.tar.gz"
echo ${pathfile//+(*\/|.*)}

일반적으로 first .에서 확장을 제거 하지만 ..경로 에서 실패 합니다.

echo **"$(basename "${pathfile%.*}")"**  
space -file.tar     # I believe we needed exatly that

중요한 참고 사항은 다음과 같습니다.

공백을 처리하기 위해 큰 따옴표 안에 큰 따옴표를 사용했습니다. 작은 문자는 $ 문자로 인해 전달되지 않습니다. 배쉬는 드물고 확장으로 인해 "두 번째"첫 번째 "따옴표"를 읽습니다.

그러나 여전히 생각해야합니다. .hidden_files

hidden="~/.bashrc"
echo "$(basename "${hidden%.*}")"  # will produce "~" !!!  

예상되는 ""결과가 아닙니다. 그것을 사용 $HOME하거나 /home/user_path/
다시하기 때문에 배쉬는 "비정상적"이고 "~"를 확장하지 마십시오 (bash BashPitfalls bash)

hidden2="$HOME/.bashrc" ;  echo '$(basename "${pathfile%.*}")'

1
#!/bin/bash
filename=program.c
name=$(basename "$filename" .c)
echo "$name"

출력 :

program

3 년 전 Steven Penny의 답변과 다른 점은 무엇입니까?
gniourf_gniourf

1

chepner answer의 의견에서 Hawker65가 지적한 것처럼 가장 투표가 많은 솔루션은 여러 확장명 (예 : filename.tar.gz)이나 경로의 나머지 점 (예 : this.path / with .dots / in.path.name). 가능한 해결책은 다음과 같습니다.

a=this.path/with.dots/in.path.name/filename.tar.gz
echo $(dirname $a)/$(basename $a | cut -d. -f1)

이것은 경로를 세지 않는 파일 이름의 첫 번째 점 앞에있는 문자를 선택하여 "tar.gz"를 제거합니다. 아마 그런 식으로 확장을 제거하고 싶지 않을 것입니다.
Frotz

0

코드와 관련된 두 가지 문제 :

  1. 변수에 저장하려는 문자열을 생성하는 명령을 둘러싸 기 위해`(백 틱) 대신 '(틱)을 사용했습니다.
  2. 변수 "$ filename"을 "cut"명령으로 파이프에 "에코"하지 않았습니다.

코드를 "name =`echo $ filename | cut -f 1 -d '.'로 변경하겠습니다. ` ", 아래와 같이 (다시 말해, 이름 변수 정의를 둘러싼 백틱을 확인하십시오) :

$> filename=foo.txt
$> echo $filename
foo.txt
$> name=`echo $filename | cut -f1 -d'.'`
$> echo $name
foo
$> 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.