如何仅显示文件名作为 cp 命令的输出?

如何仅显示文件名作为 cp 命令的输出?

我正在使用以下命令将文件从 src 文件夹复制到 dest 文件夹:

cp -nv /src/* /dest/ > copy_result.txt

复制文件的结果在输出文件中如下所示:

 « /src/test1.txt » -> « /dest/test1.txt »
 « /src/test2.txt » -> « /dest/test2.txt »

否则,我希望输出文件仅包含文件名,不包含完整路径和文件扩展名,如下所示:

test1
test2

答案1

尝试命令

cp -nv /src/* /dest/ | awk '{print $6}' | rev | cut -d/ -f1 | rev | cut -d. -f1 > copy_result.txt

awk打印第六个字段。并rev反转字符串。cut在指定的分隔符处拆分字符串-d,提取指定的部分-f

编辑:
正如指出的那样,这对于带有空格的文件/目录并不友好。但这将通过提取 '-> « ' 和 ' »' 之间的子字符串来实现:

cp -nv /src/* /dest/ | sed -e 's/.*-> « \(.*\) ».*/\1/' | rev | cut -d/ -f1 | rev | cut -d. -f1 > copy_result.txt

答案2

-vPOSIX 没有指定。这意味着每个cp实现可能会以不同的方式处理它(或根本不处理)。你cp说的« foo »我说的'foo'。可以编写一个命令,将你不想要的输出转换为想要的输出,但我仍然想提出一个独立于cp实现的解决方案。


/src/*在命令展开后,cp逐个复制结果条目。这意味着您可以将其转换cp -n /src/* /dest/

for file in /src/*; do cp -n "$file" /dest/; done

现在用 做某事很容易了$file。这将生成您想要的输出:

for path in /src/*; do
   file="${path##*/}"
   dst="/dest/$file"
   [ ! -e "$dst" ] && cp "$path" "$dst" && printf '%s\n' "${file%.*}"
done

(重定向至copy_result.txt使用done > copy_result.txt而不仅仅是done)。


请注意,如果您使用cp -r -v并且扩展中的至少一个操作数/src/*是目录,cp则会复制并打印其内容,而上面的代码(在我们添加之后-r)会复制尽可能多的内容但只打印目录本身。-r可能不是唯一会导致差异的选项。

因此,虽然该方法应该独立于cp实现,但它依赖于一些未使用的选项。另一个缺点是代码cp为 中的每个对象运行一个单独的进程/src/,这远非最佳。

还有一个竞争条件:如果$dst文件出现在[和之间cpcp它将执行其工作。您可以使用cp -n以避免覆盖,但printf仍会报告该文件。

相关内容