删除文件名中的空格和小写字母的脚本

删除文件名中的空格和小写字母的脚本

我正在尝试编写一个脚本,该脚本将用“-”替换空格,并使当前目录中的所有文件的所有字母小写。

for x in 'ls'
    do
        if [ ! -f $x ]; then
            continue
        fi

        lc = `echo $x | tr '[A-Z]' '[a-z]'`
        if [ $lc != $x ]; then
            mv $x $lc
        fi
    done

find -name "* *" -type f | rename 's/ /-/g'

我得到以下输出: call: rename from to files...

但是名称没有改变,例如:252680610243-Analyzed Sample2 2Jul12.txt

我使用 更改了权限chmod 706,这会导致问题吗?我在这里缺少什么?

这是输出bash -x lower.sh

+ for x in ''\''ls'\'''
+ '[' '!' -f ls ']'
+ continue
+ find -name '* *' -type f
+ rename 's/ /-/g'
call: rename from to files...

答案1

在 Debian 及其衍生版本(包括 Ubuntu)上,只需简单调用即可轻松实现rename:

$ touch 'A B'
$ rename 'tr/ A-Z/-a-z/' -- *
$ ls
a-b

但你的rename是一个具有相同名称的不同实用程序

答案2

您的脚本存在几个问题。

for x in 'ls'

您正在迭代包含一个单词的列表:ls。您可能打算编写`ls`(带反引号)来解析ls.不解析输出ls:如果文件名包含特殊字符(例如空格),这将不起作用。 shell 已经有一种列出目录中文件的内置方法:通配符。所以写for x in *

        if [ ! -f $x ]; then

如果文件名包含空格和其他特殊字符,这将不起作用,因为当您在$x外部写入引号时,结果会被分割成单独的单词(并且每个单词都会被解释为通配符模式,以启动)。为了避免这种效果,请放入$x双引号:if [ ! -f "$x" ]; then。你可以记住复杂的规则, 要不就始终在变量替换周围使用双引号。

由于缺少双引号,其他几行被破坏。只需将它们放在每个变量替换周围即可。

       lc = `echo $x | tr '[A-Z]' '[a-z]'`

由于等号周围有空格,这将不起作用:该行执行命令lc,并将其=作为第一个参数(和其他参数)传递。 shell 中的赋值=符号周围不能有空格。

您不需要将 的参数括起来tr。在这里,该命令恰好起作用,因为除了小写之外,您还说要替换[by[]by 。]

我建议使用美元括号$(…)而不是反引号`…`来进行命令替换。它们是等效的,只是反引号在引用其中的内容时具有复杂的规则,而$(…)具有非常直观的语法。总而言之,该命令应该是:lc=$(echo "$x" | tr A-Z a-z)

find -name "* *" -type f | rename 's/ /-/g'

您的错误消息表明您有rename来自 util-linux 包的命令而不是Perl脚本在 Debian 及其衍生版本(包括 Ubuntu)上找到。您使用的语法仅对 Perl 脚本有意义。

如果您要使用 Perl 脚本,它可以将大小写更改为小写,因此您无需事先执行此操作。并且您不需要调用,find除非您也想重命名子目录中的文件(您的第一部分不处理)。如果你想重命名当前目录下的所有文件,你可以这样写:

prename 'tr/A-Z /a-z-/' -- *

如果您只想重命名常规文件(而不是子目录、符号链接等),请使用find

find . -type f -maxdepth 1 -exec prename 'tr/A-Z /a-z-/' {} +

如果您还想对子目录中的文件进行操作,并且目录名称可能包含空格或大写字母,则必须注意不要保留它们。由于您使用的是 Linux,因此您可以使用不包含目录名称的参数进行调用-execdirprename

find . -type f -execdir prename 'tr/A-Z /a-z-/' {} +

如果您没有 Perlrename实用程序怎么办? util-linuxrename实用程序在这里无法为您提供帮助。您可以在循环中再放置一个替代品。

for x in ./*; do
  if [ -f "$x" ]; then
    y=$(echo "$x" | tr 'A-Z-' 'a-z ')
    mv "$x" "$y"
  fi
done

使用 bash,您不需要调用tr,您可以使用它的字符串替换结构。

for x in ./*; do
  if [ -f "$x" ]; then
    lc=${x,,}            # convert all letters to lowercase
    y=${lc// /-}         # replace spaces by hyphens
    if [ "$x" != "$y" ]; then
      mv "$x" "$y"
    fi
  fi
done

如果您还想对子目录中的文件进行操作,则可以使用递归 glob(由选项启用globstar)。再次强调,如果目录部分可能包含大写字母或空格,请注意不要打扰它们。

shopt -s globstar
for x in ./**/*; do
  if [ -f "$x" ]; then
    old_basename=${x##*/}
    new_basename=${old_basename,,}
    new_basename=${new_basename// /-}
    if [ "$new_basename" != "$old_basename" ]; then
      mv "${x%/*}/$old_basename" "${x%/*}/$new_basename"
    fi
  fi
done

在 zsh 中,输入autoload -U zmv您的.zshrc,您可以使用zmv全局限定符 .仅匹配常规文件和参数扩展构造对于重命名:

zmv -Q '*(.)' '${(L)f// /-}'

也可以对子目录中的文件进行操作:

zmv -Qw '**/*(.)' '$1${(L)2// /-}'

答案3

主要问题是您没有迭代文件:您正在迭代单个字符串"ls".您可能打算使用反引号而不是单引号。尽管如此,不解析ls

您还需要引用您的变量,特别是因为您知道它们包含空格。

就在 bash 中,你可以这样做:

declare -l lc    # whatever is stored in $lc is automatically lower cased
for x in *; do
    lc=${x//[[:space:]]/}  # replace all whitespace with nothing
    [ "$lc" != "$x" ] && mv -- "$x" "$lc"
done

答案4

在 Bash 4 中 ${var,,} 将 var 转换为小写:

for f in *; do f2=${f,,}; mv "$f" "${f2// /-}"; done

相关内容