我正在使用以下命令将文件从 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
-v
POSIX 没有指定。这意味着每个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
文件出现在[
和之间cp
,cp
它将执行其工作。您可以使用cp -n
以避免覆盖,但printf
仍会报告该文件。