在Bash中提取文件名和扩展名 技术背景 在Bash脚本编程中,经常需要对文件路径进行处理,提取文件名和扩展名是常见的操作。不同的文件路径格式和文件名特点(如多个扩展名、无扩展名、带特殊字符等)给提取操作带来了一定的复杂性。因此,掌握多种提取文件名和扩展名的方法是很有必要的。
实现步骤 基本方法 首先,使用basename
命令获取不包含路径的文件名: 1 2 3 filename=$(basename -- "$fullfile " ) extension="${filename##*.} " filename="${filename%.*} "
1 filename="${fullfile##*/} "
使用参数扩展 1 2 3 4 5 6 7 8 9 10 11 12 13 14 FILE="example.tar.gz" echo "${FILE%%.*} " echo "${FILE%.*} " echo "${FILE#*.} " echo "${FILE##*.} "
自定义函数实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 splitPath () { local _sp_dirname= _sp_basename= _sp_basename_root= _sp_suffix= (( $# >= 2 )) || { echo "$FUNCNAME : ERROR: Specify an input path and at least 1 output variable name." >&2; exit 2; } _sp_dirname=$(dirname "$1 " ) _sp_basename=$(basename "$1 " ) _sp_suffix=$([[ $_sp_basename = *.* ]] && printf %s ".${_sp_basename##*.} " || printf '' ) if [[ "$_sp_basename " == "$_sp_suffix " ]]; then _sp_basename_root=$_sp_basename _sp_suffix='' else _sp_basename_root=${_sp_basename%$_sp_suffix} fi [[ -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
使用sed
命令 1 2 3 4 5 FILE="a.b.js" NAME=$(echo "$FILE " | sed 's/\.[^.]*$//' ) EXTENSION=$(echo "$FILE " | sed 's/^.*\.//' )echo $NAME echo $EXTENSION
使用awk
命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 f='/path/to/complex/file.1.0.1.tar.gz' echo "$f " | awk -F'/' '{print $NF}' echo "$f " | awk -F'[.]' 'NF>1 {print $NF}' echo "$f " | awk '{sub(/[^.]*[.]/, "", $0)} 1' echo "$f " | awk -F'[.]' '{print $(NF-1)"."$NF}' echo "$f " | awk '{gsub(/.*[/]|[.].*/, "", $0)} 1' echo "$f " | awk '{gsub(/.*[/]|[.]{1}[^.]+$/, "", $0)} 1' echo "$f " | awk '{match($0, /.*[/]/, a); print a[0]}' echo "$f " | grep -Eo '.*[/]' echo "$f " | awk -F'/' '{$1=""; print $(NF-1)}' echo "$f " | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?' echo "$f " | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?' | cut -d. -f1echo "$f " | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?' | cut -d. -f2echo "$f " | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?' | cut -d. -f3echo "$f " | awk -F'[/.]' '{$1=""; print $0}' echo "$f " | grep -q '^[/]\|^~/'
核心代码 以下是一个综合的示例代码,展示了多种提取文件名和扩展名的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #!/bin/bash fullfile="/path/to/file.tar.gz" filename=$(basename -- "$fullfile " ) extension="${filename##*.} " filename="${filename%.*} " echo "方法1: 文件名 - $filename , 扩展名 - $extension " FILE="$fullfile " echo "方法2: 文件名(去除所有扩展名) - ${FILE%%.*} " echo "方法2: 文件名(去除最后一个扩展名) - ${FILE%.*} " echo "方法2: 扩展名(从第一个点开始) - ${FILE#*.} " echo "方法2: 最后一个扩展名 - ${FILE##*.} " splitPath () { local _sp_dirname= _sp_basename= _sp_basename_root= _sp_suffix= (( $# >= 2 )) || { echo "$FUNCNAME : ERROR: Specify an input path and at least 1 output variable name." >&2; exit 2; } _sp_dirname=$(dirname "$1 " ) _sp_basename=$(basename "$1 " ) _sp_suffix=$([[ $_sp_basename = *.* ]] && printf %s ".${_sp_basename##*.} " || printf '' ) if [[ "$_sp_basename " == "$_sp_suffix " ]]; then _sp_basename_root=$_sp_basename _sp_suffix='' else _sp_basename_root=${_sp_basename%$_sp_suffix} fi [[ -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 } parentpath= fname= fnameroot= suffix= splitPath "$fullfile " parentpath fname fnameroot suffixecho "方法3: 父路径 - $parentpath , 文件名 - $fname , 无后缀文件名 - $fnameroot , 后缀 - $suffix " FILE="$fullfile " NAME=$(echo "$FILE " | sed 's/\.[^.]*$//' ) EXTENSION=$(echo "$FILE " | sed 's/^.*\.//' )echo "方法4: 文件名 - $NAME , 扩展名 - $EXTENSION " f="$fullfile " filename=$(echo "$f " | awk -F'/' '{print $NF}' ) extension=$(echo "$f " | awk -F'[.]' 'NF>1 {print $NF}' )echo "方法5: 文件名 - $filename , 扩展名 - $extension "
最佳实践 使用自定义函数 :对于复杂的文件名和路径处理,使用自定义函数可以提高代码的可读性和可维护性。考虑边界情况 :在处理文件名和扩展名时,要考虑到各种边界情况,如无扩展名的文件名、以.
开头的文件名等。结合多种方法 :根据不同的需求,结合使用参数扩展、sed
、awk
等方法,可以更灵活地处理文件路径。常见问题 文件名无扩展名 :使用extension="${filename##*.}"
时,如果文件名无扩展名,会返回文件名本身。可以使用自定义函数来处理这种情况。文件名以.
开头 :filename="${filename%.*}"
在文件名以.
开头且无其他.
时,会返回空字符串。同样,可以使用自定义函数来避免这种问题。多个扩展名 :对于有多个扩展名的文件,如file.tar.gz
,要根据具体需求选择合适的提取方法。例如,使用fileExt=${fullfile#*.}; fileName=${fullfile%*.$fileExt}
可以提取完整的扩展名。