首页 > 解决方案 > 如何在unix中复制包含空格的文件名/路径?

问题描述

我的目标是搜索包含模式的文件并将其复制到文件夹中。这些文件可能在一个文件夹的多个文件夹中可用(例如 /home/abc/logs/ ....)。一些文件名和文件夹带有空格字符,包括空格。我正在尝试将找到的结果分配给一个变量并复制它。但结果是“参数列表太长”

Linux 服务器

pattern="somesttring" ;
LOG_FILE_PATH="/path/to/logs/"
LOGS_TO_COPY=$(grep -Hrn "$pattern" "$LOG_FILE_PATH" | cut -d: -f1)
cp $LOGS_TO_COPY temp #temp is folder to which i have to copy 

我收到以下错误:

cp $LOGS_TO_COPY temp/
-bash: /bin/cp: Argument list too long

标签: bashshellunixcpfile-copying

解决方案


不要将它存储在变量中,至少不是普通的字符串变量。字符串变量无法保持每个参数内的空格与分隔它们的空格之间的差异。

grep -lr "$pattern" "$LOG_FILE_PATH" | while IFS= read -r file; do cp "$file" temp/; done

另请注意,您不需要剪切 grep 结果,因为该-l标志只为您提供文件名,正是您想要的。-H是默认设置,因此不需要它,-n如果您只是要切断它,则不需要它。

如果您的文件名称中包含换行符,这将不起作用。作为一种解决方案,您可以告诉grep(and read) 使用 NUL 作为分隔符。

grep -lr --null "$pattern" "$LOG_FILE_PATH" | while IFS= read -d $'\0' -r file; do cp "$file" temp/; done

或者,您可以使用xargs而不是while+ read

grep -lr --null "$pattern" "$LOG_FILE_PATH" | xargs --null -I {} cp {} temp/

如果必须将其存储在变量中,请使用与上述相同的模式将其存储到数组变量中。这种方式不需要空格作为参数分隔符。

declare -a files
while IFS= read -d $'\0' -r file; do files+=("$file"); done < <(grep -lr --null "$pattern" "$LOG_FILE_PATH")
cp "${files[@]}" temp/

这是另一种方法(尽管如果文件名包含换行符,这将不起作用,因为mapfile不支持更改分隔符):

mapfile -t files < <(grep -lr "$pattern" "$LOG_FILE_PATH")
cp "${files[@]}" temp/

如果要复制的文件数量很大,则whilexargs解决方案仍然有效,但那些简单地将整个数组放入一个cp命令的解决方案可能不会。


推荐阅读