【问题标题】:Bash - finding files with spaces and rename with sed [duplicate]Bash - 查找带空格的文件并使用 sed 重命名 [重复]
【发布时间】:2014-02-10 12:31:26
【问题描述】:

我一直在尝试编写一个脚本来重命名所有包含空格的文件并用破折号替换空格。

示例:“Hey Bob.txt”到“Hey-Bob.txt”

当我使用 for 循环时,它只是在空格处拆分文件名,因此“Hey Bob.txt”给出了单独的参数,如“Hey”和“Bob.txt”。

我尝试了以下脚本,但它一直挂在我身上。

#!/bin/bash
find / -name '* *' -exec mv {} $(echo {} | sed 's/ /-g')\;

【问题讨论】:

  • 几乎可以肯定是引用问题,但我不确定引用 {} 是否需要或会有所帮助。值得一试,对吧?否则,回到你的循环解决方案并 dbl-quote 所有对变量的引用。祝你好运。

标签: linux bash shell sed find


【解决方案1】:

以 OP 的想法为基础:

find ${PATH_TO_FILES} -name '* *' -exec bash -c 'eval $(echo mv -v \"{}\" $(echo {} | sed "s/ /-/g"))' \;
  • 注意:需要指定PATH_TO_FILES变量

编辑:BroSlow 指出需要考虑目录结构:

find ${PATH_TO_FILES} -name '* *' -exec bash -c 'DIR=$(dirname "{}" | sed "s/ /-/g" ); BASE=$(basename "{}"); echo mv -v \"$DIR/$BASE\" \"$DIR/$(echo $BASE | sed "s/ /-/g")\"' \; > rename-script.sh ; sh rename-script.sh 

【讨论】:

  • 将添加 -type f 以避免错误,但为花哨的一个班轮 +1。
  • 我想过这个问题,但后来想:“如果 OP 想要重命名 'Hey Bob' 目录怎么办?”甚至是 'Hey Bob' 符号链接 :)
  • 也许是他想要的,但它会完全改变目录树,你仍然需要创建不存在的目录,然后才能以某种方式将文件放在一个衬垫中。所以例如“/home/foo/some space dir/some file” 将失败,即使mv 在您的上述示例中得到正确处理,因为它会尝试将mv 发送到“/home/foo/some-space-sir” /some-file"
【解决方案2】:

另一种方式:

find . -name "* *" -type f |while read file
do
  new=${file// /}
  mv "${file}" $new
done

【讨论】:

  • 如果文件名中有其他特殊字符,这不是很健壮,如果有换行符,显然根本不起作用。
【解决方案3】:

不是一行,而是避免了sed,并且如果您无论如何要将它用于脚本,它应该也能正常工作。 (如果要测试,请将mv 替换为echo

在 bash 4+ 中

#!/bin/bash
shopt -s globstar
for file in **/*; do
  filename="${file##*/}"
  if [[ -f $file && $filename == *" "* ]]; then
    onespace=$(echo $filename)
    dir="${file%/*}"
    [[ ! -f "$dir/${onespace// /-}" ]] && mv "$file" "$dir/${onespace// /-}" || echo "$dir/${onespace// /-} already exists, so not moving $file" 1>&2 
  fi
done

旧版 bash

#!/bin/bash
find . -type f -print0 | while read -r -d '' file; do
  filename="${file##*/}"
  if [[ -f $file && $filename == *" "* ]]; then
    onespace=$(echo $filename)
    dir="${file%/*}"
    [[ ! -f "$dir/${onespace// /-}" ]] && mv "$file" "$dir/${onespace// /-}" || echo "$dir/${onespace// /-} already exists, so not moving $file" 1>&2 
  fi
done

算法说明

  • **/* 这递归地列出了当前目录中的所有文件(** 在技术上是这样做的,但 /* 是在末尾添加的,因此它不会列出目录本身)
  • ${file##*/} 将在文件中搜索最长的*/ 模式并将其从字符串中删除。例如/foo/bar/test.txt 打印为 test.txt
  • $(echo $filename) 不引用 echo 会将空格截断为 1,从而更容易用一个 - 替换 任何 个空格
  • ${file%/*} 删除包括最后一个 / 之后的所有内容,例如/foo/bar/test.txt 打印 /foo/bar
  • mv "$file" ${onespace// /-}- 替换我们文件名中的每个空格(我们事先检查是否存在连字符版本,如果它确实回显它未能通过stderr,请注意&& 在bash 中的|| 之前处理)
  • find . -type f -print0 | while read -r -d '' file 这用于通过设置分隔符而不处理 \ 来避免将带有空格的字符串分解

样本输出

$ tree
.
├── bar
│   ├── some dir
│   │   ├── some-name-without-space1.pdf
│   │   ├── some name with space1.pdf
│   ├── some-name-without-space1.pdf
│   ├── some name with space1.pdf
│   └── some-name-with-space1.pdf
└── space.sh
$ ./space.sh
bar/some-name-with-space1.pdf already exists, so not moving bar/some name with space1.pdf
$ tree
.
├── bar
│   ├── some dir
│   │   ├── some-name-without-space1.pdf
│   │   ├── some-name-with-space1.pdf
│   ├── some-name-without-space1.pdf
│   ├── some name with space1.pdf
│   └── some-name-with-space1.pdf
└── space.sh

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-09
    • 2021-05-26
    • 2018-03-28
    • 2020-10-08
    • 2010-11-16
    • 1970-01-01
    • 2013-02-07
    • 2016-01-25
    相关资源
    最近更新 更多