使用 bash 我需要删除文件名中文件扩展名之前的尾随空格
Using bash I need to remove trailing spaces before a file extension in file names
我有数百个文件看起来类似于:
"QDN34 Unit5 mark-up - Judy .pdf"
"QDN34 Unit7 mark-up - Judy .pdf"
"file with two character ext .ai"
"file with dot. trailing space and no ext "
"file with no ext"
请注意,除了最后一个以外,所有文件的末尾都有一个 space,不包括相关的文件扩展名。
我需要在文件名中保留 spaces(不理想)并删除那些尾随的 spaces。
结果 应该是:
"QDN34 Unit5 mark-up - Judy.pdf"
"QDN34 Unit7 mark-up - Judy.pdf"
"file with two character ext.ai"
"file with dot. trailing space and no ext"
"file with no ext"
到目前为止我有:
newName=$(find . -type f -name \*\ .* | cut -d'.' -f2 | sed 's/\ $//' | sed 's/^\/*//')
extens=$(find . -type f -name \*\ .* | sed 's@.*/.*\.@.@')
oldName=$(find . -type f -iname \*\ .* | sed 's/^\.\/*//')
for f in "$oldName" ; do mv -nv "$oldName" "$newName""$extens" ; done
但是我收到了看起来索引不匹配的错误。感觉我应该使用数组,但我不确定如何。
输出是:
mv: rename file with two character ext .ai
QDN34 Unit5 mark-up - Judy .pdf
QDN34 Unit7 mark-up - Judy .pdf to file with two character ext
QDN34 Unit5 mark-up - Judy
QDN34 Unit7 mark-up - Judy.ai
.pdf
.pdf: No such file or directory
您可以尝试使用 prename
实用程序 perl regular expression:
user@host $ prename 's/\s(\..+$)//g' *
\s
- 表示 space 个字符
\.
- 表示点
.
- 表示一个字符
+$
- 表示重复前一个符号直到行尾
</code> - 表示替换为表达式
在 <code>()
如果您没有此实用程序,您可以使用以下 bash 脚本:
# you can replace the "*" in the line below
# with any necessary find or ls command to rename only necessary files
for old_name in *;
do
new_name=$(echo "$old_name"|sed 's/ \(\.[^ \t]*$\)//g')
echo "\"$old_name\" --> \"$new_name\""
mv "$old_name" "$new_name"
done
#!/bin/bash
IFS=$(echo -en "\n\b") && for a in $(ls -f1 *); do
file_ext="${a##*.}"
if [[ ! -z "${file_ext}" && ${#file_ext} -lt 4 ]]; then
file_base="${a%.*}"
else
file_base="${a}"
file_ext=""
fi
[ "${file_base:$((${#file_base}-1)):1}" = " " ] && \
file_base="${file_base% *}"
new_file="${file_base}${file_ext:+.}${file_ext}"
if [ ! "${new_file}" = "${a}" ]; then
echo "mv -nv \"$a\" \"${new_file}\""
#mv -nv "${a}" "${file_base}.${file_ext}"
fi
done
您可以 运行 这个 bash 脚本安全地放在您要重命名它们的目录中,看看它会做什么,然后如果它能完成您想要的,您可以取消注释真正的移动命令并重新运行它。
根据 OP 评论更新 - 此脚本认为 .
必须处理右侧最多 3(小于 4)的文件扩展名,更改它以反映您的数据集。
试试这个:
find . -type f | while read i; do mv "$i" "$(sed 's/ \.\([a-z0-9]*\)$/\./' <<< "$i")"; done;
对于每个文件(从当前目录递归),删除文件扩展名前的 space(使用 sed
),然后用新名称重命名原始文件([=11 的结果) =]命令)。
一个Bash解决方案
这是一个 Bash 解决方案也可能有用的解决方案。以下测试在脚本中使用 extsz
设置的扩展 (max 4 chars + .
)。如果找到扩展名,脚本会删除文件名中的空格,然后将文件从旧名称移动到新名称(实际移动在下面进行了评论)。它依赖于 参数 expansion/substring 替换 来操作空格和文件名:
#!/bin/bash
declare -i extsz=-5 # extension w/i last 4 chars
## trim leading/trailing whitespace
function trimws {
[ -z "" ] && return 1
local strln="${#1}"
[ "$strln" -lt 2 ] && return 1
local trimstr=
trimstr="${trimstr#"${trimstr%%[![:space:]]*}"}" # remove leading whitespace characters
trimstr="${trimstr%"${trimstr##*[![:space:]]}"}" # remove trailing whitespace characters
printf "%s" "$trimstr"
return 0
}
## for each filename read from stdin
while read -r ffname || test -n "$ffname" ; do
## test for extension and set 'ext' if present
for ((i=$extsz; i<0; i++)); do
[ "${ffname:(i):1}" == '.' ] && { ext=${ffname:(i)}; break; }
done
## if extension, move the file to name w/o trailing space w/orig extension
if [ -n "$ext" ]; then
fname="${ffname%.*}" # separate filename from extension
fnwosp="$(trimws "$fname")" # trim whitespace from filename
printf " renaming : '%s' -> '%s'\n" "$ffname" "${fnwosp}${ext}"
#mv "$ffname" "${fnwosp}${ext}" # commented for testing
else
## if no extension, just trim whitespace and move
printf " renaming : '%s' -> '%s'\n" "$ffname" "$(trimws "$ffname")"
# mv "$ffname" "$(trimws "$ffname")"
fi
unset ext # unset 'ext' for next iteration
done
exit 0
输入
$ cat dat/wfname.txt
QDN34 Unit5 mark-up - Judy .pdf
QDN34 Unit7 mark-up - Judy .pdf
file with two character ext .ai
file with dot. trailing space and no ext
file with no ext
输出
$ bash fixfilenames.sh <dat/wfname.txt
renaming : 'QDN34 Unit5 mark-up - Judy .pdf' -> 'QDN34 Unit5 mark-up - Judy.pdf'
renaming : 'QDN34 Unit7 mark-up - Judy .pdf' -> 'QDN34 Unit7 mark-up - Judy.pdf'
renaming : 'file with two character ext .ai' -> 'file with two character ext.ai'
renaming : 'file with dot. trailing space and no ext' -> 'file with dot. trailing space and no ext'
renaming : 'file with no ext' -> 'file with no ext'
注意: 从 stdin
读取时,shell 将去除没有扩展名的文件名的尾随空格。
读取文件名作为参数
为了说明从没有扩展名的文件名末尾删除空格,有必要引用和读取文件名作为参数。如果那是您所需要的,这里有替代品。无论如何,将文件名作为参数而不是从标准输入中批量读取可能更有意义:
#!/bin/bash
declare -i extsz=-5 # extension w/i last 4 chars
## trim leading/trailing whitespace
function trimws {
[ -z "" ] && return 1
local strln="${#1}"
[ "$strln" -lt 2 ] && return 1
local trimstr=
trimstr="${trimstr#"${trimstr%%[![:space:]]*}"}" # remove leading whitespace characters
trimstr="${trimstr%"${trimstr##*[![:space:]]}"}" # remove trailing whitespace characters
printf "%s" "$trimstr"
return 0
}
## test at least 1 command line argument
[ $# -gt 0 ] || {
printf "error: insufficient input. usage: %s <filename>\n" "${0##*/}"
exit 1
}
## for each of the filenames give as arguments
for ffname in "$@"; do
## test for extension and set 'ext' if present
for ((i=$extsz; i<0; i++)); do
[ "${ffname:(i):1}" == '.' ] && { ext=${ffname:(i)}; break; }
done
## if extension, move the file to name w/o trailing space w/orig extension
if [ -n "$ext" ]; then
fname="${ffname%.*}" # separate filename from extension
fnwosp="$(trimws "$fname")" # trim whitespace from filename
printf " renaming : '%s' -> '%s'\n" "$ffname" "${fnwosp}${ext}"
#mv "$ffname" "${fnwosp}${ext}" # commented for testing
else
## if no extension, just trim whitespace and move
printf " renaming : '%s' -> '%s'\n" "$ffname" "$(trimws "$ffname")"
# mv "$ffname" "$(trimws "$ffname")"
fi
unset ext
done
exit 0
例子
$ bash fixfilenames.sh 'testfile w end space '
renaming : 'testfile w end space ' -> 'testfile w end space'
$ bash fixfilenames.sh 'file with two character ext .ai'
renaming : 'file with two character ext .ai' -> 'file with two character ext.ai'
我有数百个文件看起来类似于:
"QDN34 Unit5 mark-up - Judy .pdf"
"QDN34 Unit7 mark-up - Judy .pdf"
"file with two character ext .ai"
"file with dot. trailing space and no ext "
"file with no ext"
请注意,除了最后一个以外,所有文件的末尾都有一个 space,不包括相关的文件扩展名。
我需要在文件名中保留 spaces(不理想)并删除那些尾随的 spaces。
结果 应该是:
"QDN34 Unit5 mark-up - Judy.pdf"
"QDN34 Unit7 mark-up - Judy.pdf"
"file with two character ext.ai"
"file with dot. trailing space and no ext"
"file with no ext"
到目前为止我有:
newName=$(find . -type f -name \*\ .* | cut -d'.' -f2 | sed 's/\ $//' | sed 's/^\/*//')
extens=$(find . -type f -name \*\ .* | sed 's@.*/.*\.@.@')
oldName=$(find . -type f -iname \*\ .* | sed 's/^\.\/*//')
for f in "$oldName" ; do mv -nv "$oldName" "$newName""$extens" ; done
但是我收到了看起来索引不匹配的错误。感觉我应该使用数组,但我不确定如何。
输出是:
mv: rename file with two character ext .ai
QDN34 Unit5 mark-up - Judy .pdf
QDN34 Unit7 mark-up - Judy .pdf to file with two character ext
QDN34 Unit5 mark-up - Judy
QDN34 Unit7 mark-up - Judy.ai
.pdf
.pdf: No such file or directory
您可以尝试使用 prename
实用程序 perl regular expression:
user@host $ prename 's/\s(\..+$)//g' *
\s
- 表示 space 个字符\.
- 表示点.
- 表示一个字符+$
- 表示重复前一个符号直到行尾</code> - 表示替换为表达式 在 <code>()
如果您没有此实用程序,您可以使用以下 bash 脚本:
# you can replace the "*" in the line below
# with any necessary find or ls command to rename only necessary files
for old_name in *;
do
new_name=$(echo "$old_name"|sed 's/ \(\.[^ \t]*$\)//g')
echo "\"$old_name\" --> \"$new_name\""
mv "$old_name" "$new_name"
done
#!/bin/bash
IFS=$(echo -en "\n\b") && for a in $(ls -f1 *); do
file_ext="${a##*.}"
if [[ ! -z "${file_ext}" && ${#file_ext} -lt 4 ]]; then
file_base="${a%.*}"
else
file_base="${a}"
file_ext=""
fi
[ "${file_base:$((${#file_base}-1)):1}" = " " ] && \
file_base="${file_base% *}"
new_file="${file_base}${file_ext:+.}${file_ext}"
if [ ! "${new_file}" = "${a}" ]; then
echo "mv -nv \"$a\" \"${new_file}\""
#mv -nv "${a}" "${file_base}.${file_ext}"
fi
done
您可以 运行 这个 bash 脚本安全地放在您要重命名它们的目录中,看看它会做什么,然后如果它能完成您想要的,您可以取消注释真正的移动命令并重新运行它。
根据 OP 评论更新 - 此脚本认为 .
必须处理右侧最多 3(小于 4)的文件扩展名,更改它以反映您的数据集。
试试这个:
find . -type f | while read i; do mv "$i" "$(sed 's/ \.\([a-z0-9]*\)$/\./' <<< "$i")"; done;
对于每个文件(从当前目录递归),删除文件扩展名前的 space(使用 sed
),然后用新名称重命名原始文件([=11 的结果) =]命令)。
一个Bash解决方案
这是一个 Bash 解决方案也可能有用的解决方案。以下测试在脚本中使用 extsz
设置的扩展 (max 4 chars + .
)。如果找到扩展名,脚本会删除文件名中的空格,然后将文件从旧名称移动到新名称(实际移动在下面进行了评论)。它依赖于 参数 expansion/substring 替换 来操作空格和文件名:
#!/bin/bash
declare -i extsz=-5 # extension w/i last 4 chars
## trim leading/trailing whitespace
function trimws {
[ -z "" ] && return 1
local strln="${#1}"
[ "$strln" -lt 2 ] && return 1
local trimstr=
trimstr="${trimstr#"${trimstr%%[![:space:]]*}"}" # remove leading whitespace characters
trimstr="${trimstr%"${trimstr##*[![:space:]]}"}" # remove trailing whitespace characters
printf "%s" "$trimstr"
return 0
}
## for each filename read from stdin
while read -r ffname || test -n "$ffname" ; do
## test for extension and set 'ext' if present
for ((i=$extsz; i<0; i++)); do
[ "${ffname:(i):1}" == '.' ] && { ext=${ffname:(i)}; break; }
done
## if extension, move the file to name w/o trailing space w/orig extension
if [ -n "$ext" ]; then
fname="${ffname%.*}" # separate filename from extension
fnwosp="$(trimws "$fname")" # trim whitespace from filename
printf " renaming : '%s' -> '%s'\n" "$ffname" "${fnwosp}${ext}"
#mv "$ffname" "${fnwosp}${ext}" # commented for testing
else
## if no extension, just trim whitespace and move
printf " renaming : '%s' -> '%s'\n" "$ffname" "$(trimws "$ffname")"
# mv "$ffname" "$(trimws "$ffname")"
fi
unset ext # unset 'ext' for next iteration
done
exit 0
输入
$ cat dat/wfname.txt
QDN34 Unit5 mark-up - Judy .pdf
QDN34 Unit7 mark-up - Judy .pdf
file with two character ext .ai
file with dot. trailing space and no ext
file with no ext
输出
$ bash fixfilenames.sh <dat/wfname.txt
renaming : 'QDN34 Unit5 mark-up - Judy .pdf' -> 'QDN34 Unit5 mark-up - Judy.pdf'
renaming : 'QDN34 Unit7 mark-up - Judy .pdf' -> 'QDN34 Unit7 mark-up - Judy.pdf'
renaming : 'file with two character ext .ai' -> 'file with two character ext.ai'
renaming : 'file with dot. trailing space and no ext' -> 'file with dot. trailing space and no ext'
renaming : 'file with no ext' -> 'file with no ext'
注意: 从 stdin
读取时,shell 将去除没有扩展名的文件名的尾随空格。
读取文件名作为参数
为了说明从没有扩展名的文件名末尾删除空格,有必要引用和读取文件名作为参数。如果那是您所需要的,这里有替代品。无论如何,将文件名作为参数而不是从标准输入中批量读取可能更有意义:
#!/bin/bash
declare -i extsz=-5 # extension w/i last 4 chars
## trim leading/trailing whitespace
function trimws {
[ -z "" ] && return 1
local strln="${#1}"
[ "$strln" -lt 2 ] && return 1
local trimstr=
trimstr="${trimstr#"${trimstr%%[![:space:]]*}"}" # remove leading whitespace characters
trimstr="${trimstr%"${trimstr##*[![:space:]]}"}" # remove trailing whitespace characters
printf "%s" "$trimstr"
return 0
}
## test at least 1 command line argument
[ $# -gt 0 ] || {
printf "error: insufficient input. usage: %s <filename>\n" "${0##*/}"
exit 1
}
## for each of the filenames give as arguments
for ffname in "$@"; do
## test for extension and set 'ext' if present
for ((i=$extsz; i<0; i++)); do
[ "${ffname:(i):1}" == '.' ] && { ext=${ffname:(i)}; break; }
done
## if extension, move the file to name w/o trailing space w/orig extension
if [ -n "$ext" ]; then
fname="${ffname%.*}" # separate filename from extension
fnwosp="$(trimws "$fname")" # trim whitespace from filename
printf " renaming : '%s' -> '%s'\n" "$ffname" "${fnwosp}${ext}"
#mv "$ffname" "${fnwosp}${ext}" # commented for testing
else
## if no extension, just trim whitespace and move
printf " renaming : '%s' -> '%s'\n" "$ffname" "$(trimws "$ffname")"
# mv "$ffname" "$(trimws "$ffname")"
fi
unset ext
done
exit 0
例子
$ bash fixfilenames.sh 'testfile w end space '
renaming : 'testfile w end space ' -> 'testfile w end space'
$ bash fixfilenames.sh 'file with two character ext .ai'
renaming : 'file with two character ext .ai' -> 'file with two character ext.ai'