Bash.命令替换的不良结果

问题描述 投票:0回答:1

我想替换文件名中的空格。我的测试目录中包含有空格的文件。

$ ls
'1 2 3.txt'  '4 5.txt'  '6 7 8 9.txt'

比如这段代码就很好用

$ printf "$(printf 'spaces in file name.txt' | sed 's/ /_/g')"
spaces_in_file_name.txt

我把下划线上的空格替换掉,然后命令替换的结果是双引号作为文本。在接下来的情况下,这种重要的替换结构是必不可少的。诸如以下命令 找到xargs 有代入感 {}大括号)。因此接下来的命令可以替换文件中的空格。

$ find ./ -name "*.txt" -print0 | xargs --null -I '{}' mv '{}' "$( printf '{}' | sed 's/ /_/g' )"
mv: './6 7 8 9.txt' and './6 7 8 9.txt' are the same file
mv: './4 5.txt' and './4 5.txt' are the same file
mv: './1 2 3.txt' and './1 2 3.txt' are the same file

但我得到的是错误。为了更清楚地考虑到错误,我将用 mv 我只是用 回响(或 printf):

$ find ./ -name "*.txt" -print0 | xargs --null -I '{}' echo "$( printf '{}' | sed 's/ /_/g' )"
./6 7 8 9.txt
./4 5.txt
./1 2 3.txt

正如我们所看到的,下划线上的空格没有被替换。但是如果没有命令替换,替换的结果是正确的。

$ find ./ -name "*.txt" -print0 | xargs --null -I '{}' printf '{}\n' | sed 's/ /_/g'
./6_7_8_9.txt
./4_5.txt
./1_2_3.txt

所以命令替换的事实是 大括号 破坏了结果(因为第一条命令的结果是正确的),但如果不替换命令,结果是正确的。但是为什么呢?

bash sed find xargs
1个回答
1
投票

你的命令替换运行 之前 find 而你正在执行

mv '{}' "{}"

你可以改变 find 命令,以匹配 .txt 文件中至少有一个空格字符,并使用 -exec 和一个小的bash脚本来重命名这些文件。

find . -type f -name "* *.txt" -exec bash -c '
  for file; do
    fname=${file##*/}
    mv -i "$file" "${file%/*}/${fname// /_}"
  done
' bash {} +
  • ${file##*/} 删除父目录(最长的前缀模式) */),并留下文件名(如 basename 命令)
  • ${file%/*} 删除文件名(最短后缀模式) /*),并留下父目录(如 dirname 命令)
  • ${fname// /_} 用下划线代替所有空格

0
投票

这是很快速和简单的循环,只需替换为 absolute_path 与你的路径。

for f in absolute_path/*.txt; do mv "$f" "${f// /_}";done

${f// /_} 部分利用bash的参数扩展机制,用提供的字符串替换参数中的模式。

© www.soinside.com 2019 - 2024. All rights reserved.