while循环期间“cp:目标'...'不是目录”

while循环期间“cp:目标'...'不是目录”

我有一个要缩短其名称的文件目录:

(3) andrew@andrew Learning_Plans $ ls -al
total 580
drwxr-xr-x 2 andrew andrew  4096 Apr 10 21:40 .
drwxr-xr-x 7 andrew andrew  4096 Apr 10 16:46 ..
-rw-rw-rw- 1 andrew andrew 17825 Mar 25 14:18 Edexcel International GCSE Physics Chapter 10 Properties of Waves Learning Plan.docx
-rw-rw-rw- 1 andrew andrew 18472 Mar 25 14:19 Edexcel International GCSE Physics Chapter 11 The Electromagnetic Spectrum Learning Plan.docx
-rw-rw-rw- 1 andrew andrew 18692 Mar 25 14:19 Edexcel International GCSE Physics Chapter 12 Light Waves Learning Plan.docx
:
etc

我从命令行运行了以下命令:

while read x; do echo cp \'$x\' $(echo $x | cut -b38- | tr ' ' '_'); done < <(find . -type f)

这产生了我所期望的:

cp './Edexcel International GCSE Physics Chapter 17 Energy Resources and Electricity Generation Learning Plan.docx' Chapter_17_Energy_Resources_and_Electricity_Generation_Learning_Plan.docx
cp './Edexcel International GCSE Physics Chapter 19 Solids, Liquids and Gases Learning Plan.docx' Chapter_19_Solids,_Liquids_and_Gases_Learning_Plan.docx
cp './Edexcel International GCSE Physics Chapter 28 Cosmology Learning Plan.docx' Chapter_28_Cosmology_Learning_Plan.docx
:
etc

然而,去除回声给出:

cp: target ‘Chapter_17_Energy_Resources_and_Electricity_Generation_Learning_Plan.docx’ is not a directory
cp: target ‘Chapter_19_Solids,_Liquids_and_Gases_Learning_Plan.docx’ is not a directory
cp: target ‘Chapter_28_Cosmology_Learning_Plan.docx’ is not a directory
:
etc

我猜这与文件名中的空格有关,但我认为单引号可以解决这个问题?

我尝试将 echo 的输出复制/粘贴回终端,并且运行正常!它只是不会在 while 循环中运行。

版本:

(3) andrew@andrew Learning_Plans $ bash --version
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
(3) andrew@andrew Learning_Plans $ cat /etc/*release
DISTRIB_ID=LinuxMint
DISTRIB_RELEASE=17.3
DISTRIB_CODENAME=rosa
DISTRIB_DESCRIPTION="Linux Mint 17.3 Rosa"
NAME="Ubuntu"
VERSION="14.04, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"

答案1

问题在于文件名中的空格。文件名以空格分隔。当cp获取两个以上参数时,最后一个参数必须是目录。事实并非如此,所以它抱怨。

要从每个文件名中删除Edexcel International GCSE Physics字符串并以安全的方式将空格转换为下划线,请使用 (in bash)

for name in 'Edexcel International GCSE Physics '*.docx; do
    newname=${name#Edexcel International GCSE Physics }
    newname=${newname// /_}

    mv -i "$name" "$newname"
done

这将迭代当前目录中的所有相关文件,并newname通过首先删除名称开头的已知子字符串,然后将剩余的空格转换为下划线,在变量中创建一个新名称。然后将旧名称重命名为新名称。

如果您确实想创建文件的副本(如在您的代码中),请将 更改为mvcp

测试:

$ ls
Edexcel International GCSE Physics Chapter 10 Properties of Waves Learning Plan.docx
Edexcel International GCSE Physics Chapter 11 The Electromagnetic Spectrum Learning Plan.docx
Edexcel International GCSE Physics Chapter 12 Light Waves Learning Plan.docx

(循环在这里运行)

$ ls
Chapter_10_Properties_of_Waves_Learning_Plan.docx
Chapter_11_The_Electromagnetic_Spectrum_Learning_Plan.docx
Chapter_12_Light_Waves_Learning_Plan.docx

您是否想在多个子目录上递归地应用此功能:

find . -type f -name 'Edexcel International GCSE Physics *.docx' -exec sh -c '
    for pathname; do
        name=$(basename "$pathname")

        newname=${name#Edexcel International GCSE Physics }
        newname=${newname// /_}

        mv -i "$pathname" "$(dirname "$pathname")/$newname"
    done' sh {} +

有关的:

相关内容