簡體   English   中英

如何在 shell 腳本中刪除文件名的擴展名?

[英]How can I remove the extension of a filename in a shell script?

以下代碼有什么問題?

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

照原樣,我得到文字字符串$filename | cut -f1 -d'.' $filename | cut -f1 -d'.' ,但如果我刪除引號,我將一無所獲。 同時,鍵入

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

在 shell 中給了我我想要的輸出, test 我已經知道$filename已分配正確的值。 我想要做的是將沒有擴展名的文件名分配給變量。

您還可以使用參數擴展:

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

請注意,如果沒有文件擴展名,它將進一步查找點,例如

  • 如果文件名僅以點開頭(例如.bashrc ),它將刪除整個文件名。
  • 如果路徑中只有一個點(例如path.to/myfile./myfile ),那么它將在路徑內修剪。

當您想在腳本/命令中執行命令時,您應該使用命令替換語法$(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

如果您知道擴展名,則可以使用basename

$ basename /home/jsmith/base.wiki .wiki
base

如果您的文件名包含一個點(擴展名除外),請使用以下命令:

echo $filename | rev | cut -f 2- -d '.' | rev
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

使用任何你想要的。 在這里,我假設最后. (點)后跟文本是擴展名。

僅使用 POSIX 的內置:

#!/usr/bin/env sh
path=this.path/with.dots/in.path.name/filename.tar.gz

# Get the basedir without external command
# by stripping out shortest trailing match of / followed by anything
dirname=${path%/*}

# Get the basename without external command
# by stripping out longest leading match of anything followed by /
basename=${path##*/}

# Strip uptmost trailing extension only
# by stripping out shortest trailing match of dot followed by anything
oneextless=${basename%.*}; echo "$noext" 

# Strip all extensions
# by stripping out longest trailing match of dot followed by anything
noext=${basename%%.*}; echo "$noext"

# Printout demo
printf %s\\n "$path" "$dirname" "$basename" "$oneextless" "$noext"

打印演示:

this.path/with.dots/in.path.name/filename.tar.gz
this.path/with.dots/in.path.name
filename.tar.gz
filename.tar
filename
#!/bin/bash
file=/tmp/foo.bar.gz
echo $file ${file%.*}

輸出:

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

請注意,僅刪除了最后一個擴展名。

我的建議是使用basename
它在 Ubuntu 中是默認的,視覺上簡單的代碼並處理大多數情況。

以下是處理空格和多點/子擴展的一些子案例:

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

它通常從 first 擺脫擴展. ,但在我們的..路徑中失敗

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

這里有一個重要的注意事項:

我在雙引號內使用雙引號來處理空格。 由於發短信 $,單引號不會通過。 Bash 是不尋常的,並且由於擴展而讀取“第二個“第一個”引號。

但是,您仍然需要考慮.hidden_files

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

不是預期的“”結果。 要實現它,請使用$HOME/home/user_path/
因為 bash 再次是“不尋常的”並且不要擴展“~”(搜索 bash BashPitfalls)

hidden2="$HOME/.bashrc" ;  echo '$(basename "${pathfile%.*}")'
#!/bin/bash
filename=program.c
name=$(basename "$filename" .c)
echo "$name"

輸出:

program

正如 Hawker65 在 chepner answer 的評論中指出的那樣,投票最多的解決方案既不處理多個擴展名(例如 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)

先前提供的答案在包含點的路徑方面存在問題。 一些例子:

/xyz.dir/file.ext
./file.ext
/a.b.c/x.ddd.txt

我更喜歡使用|sed -e 's/\\.[^./]*$//' 例如:

$ echo "/xyz.dir/file.ext" | sed -e 's/\.[^./]*$//'
/xyz.dir/file
$ echo "./file.ext" | sed -e 's/\.[^./]*$//'
./file
$ echo "/a.b.c/x.ddd.txt" | sed -e 's/\.[^./]*$//'
/a.b.c/x.ddd

注意:如果要刪除多個擴展名(如上一個示例),請使用|sed -e 's/\\.[^/]*$//'

$ echo "/a.b.c/x.ddd.txt" | sed -e 's/\.[^/]*$//'
/a.b.c/x

但是,此方法將在沒有擴展名的“點文件”中失敗:

$ echo "/a.b.c/.profile" | sed -e 's/\.[^./]*$//'
/a.b.c/

要涵蓋此類情況,您可以使用:

$ echo "/a.b.c/.profile" | sed -re 's/(^.*[^/])\.[^./]*$/\1/'
/a.b.c/.profile

您的代碼有兩個問題:

  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
$> 

如果我錯了請指正。 當我嘗試通過CLI(命令行界面)對文件進行任何更新時,請執行以下操作:

1-例如,我現在有一個文件test.txt可以很好地創建:

touch test.txt

2-現在我可以使用以下命令備份文件了:

cp test.txt{,.bak}

3-免於查看目錄

ll

我們現在很好地找到了兩個文件test.txt和test.txt.bak

4-現在,如果我們在內部出錯,我們可以刪除原始文件test.txt

rm test.txt

5-下面的命令很好地從備份中還原原始文件

cp test.txt.bak test.txt

6-如果我們現在列出目錄文件,我們可以找到test.txt和test.txt.bak:

ll

7-現在刪除test.txt.bak,不再需要,如下所示

rm test.txt.bak

8-您在安全方面進行了更新。

這個涵蓋了所有的可能性! (路徑中是否有點;有擴展名或沒有擴展名):

tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*});echo $filename_noextension

筆記:

  • 它為您提供沒有任何擴展名的文件名。 所以$filename_noextension變量中沒有路徑。
  • 您最終會得到兩個不需要的變量$tmp1$tmp2 確保您沒有在腳本中使用它們。

測試示例:

filename=.bashrc; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=.bashrc.txt; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=.bashrc.txt.tar; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=~/.bashrc; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=~/.bashrc.txt.tar; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=bashrc; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=bashrc.txt; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=bashrc.txt.tar; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=~/bashrc; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=~/bashrc.txt.tar; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

在此處輸入圖片說明

假設您的文件具有 .new 擴展名

ls -1 | awk '{ print "mv "$1" `basename "$1" .new`"}' | sh

由於發布后沒有顯示特殊報價,請參見圖片。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM