如何用反斜杠和 space "\ " 替换 space 以便 bash shell 脚本可以从 .tsv 文件中读取文件名并执行 rsync 复制
How to replace a space with backslash and space "\ " so bash shell script can read the file name from a .tsv file and perform rsync copy
我有一个脚本,它从由 space 分隔的 tsv 文件中获取源和目标信息。第一列表示源文件路径,第二列是目标。我的 rsync 命令读取源和目标信息并执行复制操作。
但问题是源文件和目标文件都包含带有白色 space (header-background copy.jpg) 的文件名,而我们知道当 bash shell读取文件名(带space),它将space替换为反斜杠后跟space“\”
/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background copy.jpg /mapped-data/data20/data3/header-background copy.jpg
我的问题是如何将 space 替换为“\”,以便 shell 可以读取它。我尝试使用下面的 sed 命令
sed -r 's/^\s+//;s/\s+/\ /g' test2.tsv
但是有一个问题,上面的 sed 命令还在源路径后面添加了一个反斜杠。正如我所提到的,我的脚本从 .tsv 文件中获取源和目标信息,因此添加斜杠在这里是一个问题。下面是 sed 命令的输出。
/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background\ copy.jpg\ /mapped-data/data20/data3/header-background\ copy.jpg
我想要的是隐蔽的东西
/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background copy.jpg /mapped-data/data20/data3/header-background copy.jpg
到
/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background\ copy.jpg /mapped-data/data20/data3/header-background\ copy.jpg
tsv file separated by space
至少使用 tab
,因为 tab
比 space
.
更不可能出现在路径中
备注:你知道吗只有/
和[=17=]
(NULL byte) 是 Linux 文件系统中文件名的禁用字符?这意味着除 [=17=]
之外的所有内容都可以出现在路径中...
假设您的文件现在是 tab
定界的,并且您的路径不包括 newlines
和 tabs
。 BASH:
阅读方法
while IFS=$'\t' read -r filepath1 filepath2
do
declare -p filepath1 filepath2
done <<< "/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background copy.jpg"$'\t'"/mapped-data/data20/data3/header-background copy.jpg"
输出:
declare -- filepath1="/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background copy.jpg"
declare -- filepath2="/mapped-data/data20/data3/header-background copy.jpg"
如果你需要明确地转义一个变量(例如在scp
或rsync
的远程部分)那么你可以使用printf '%q'
像这样:
rsync -av "$filepath1" user@server:"$(printf '%q' "$filepath2")"
使用 sed
,一种方法是将匹配项分组,然后 return 使用附加反斜杠的反向引用
sed 's/\([A-Za-z0-9\/][^\.]*\) /\ /g' input_file
/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background\ copy.jpg /mapped-data/data20/data3/header-background\ copy.jpg
使用参数替换拆分列:
while IFS= read -r line; do
# count raw tabs to validate format
tabs=${line//[!$'\t']}
tabs=${#tabs}
if ((tabs!=1)); then
echo "${line//$'\t'/TAB}: less or more than one raw tab, skipping…" >&2
else
# split by tab
source=${line%$'\t'*}
target=${line#*$'\t'}
rsync "$source" "$target"
fi
done < list.tsv
循环检查每一行是否只有一个制表符,如果没有则跳过。添加您的 rsync
选项等
确保列表没有符号转义字符(如 \t
或 \n
),或任何其他不属于文字文件名的 escapes/quotes。 tsv
和 csv
可以有各种不同的非文字引用,需要正确解析。
另请注意 rsync
的用法,用于将文件名从列表文件复制到单个目标:rsync [opts] —files-from="my-source-list" /my/target/
我有一个脚本,它从由 space 分隔的 tsv 文件中获取源和目标信息。第一列表示源文件路径,第二列是目标。我的 rsync 命令读取源和目标信息并执行复制操作。
但问题是源文件和目标文件都包含带有白色 space (header-background copy.jpg) 的文件名,而我们知道当 bash shell读取文件名(带space),它将space替换为反斜杠后跟space“\”
/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background copy.jpg /mapped-data/data20/data3/header-background copy.jpg
我的问题是如何将 space 替换为“\”,以便 shell 可以读取它。我尝试使用下面的 sed 命令
sed -r 's/^\s+//;s/\s+/\ /g' test2.tsv
但是有一个问题,上面的 sed 命令还在源路径后面添加了一个反斜杠。正如我所提到的,我的脚本从 .tsv 文件中获取源和目标信息,因此添加斜杠在这里是一个问题。下面是 sed 命令的输出。
/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background\ copy.jpg\ /mapped-data/data20/data3/header-background\ copy.jpg
我想要的是隐蔽的东西
/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background copy.jpg /mapped-data/data20/data3/header-background copy.jpg
到
/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background\ copy.jpg /mapped-data/data20/data3/header-background\ copy.jpg
tsv file separated by space
至少使用 tab
,因为 tab
比 space
.
备注:你知道吗只有/
和[=17=]
(NULL byte) 是 Linux 文件系统中文件名的禁用字符?这意味着除 [=17=]
之外的所有内容都可以出现在路径中...
假设您的文件现在是 tab
定界的,并且您的路径不包括 newlines
和 tabs
。 BASH:
while IFS=$'\t' read -r filepath1 filepath2
do
declare -p filepath1 filepath2
done <<< "/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background copy.jpg"$'\t'"/mapped-data/data20/data3/header-background copy.jpg"
输出:
declare -- filepath1="/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background copy.jpg"
declare -- filepath2="/mapped-data/data20/data3/header-background copy.jpg"
如果你需要明确地转义一个变量(例如在scp
或rsync
的远程部分)那么你可以使用printf '%q'
像这样:
rsync -av "$filepath1" user@server:"$(printf '%q' "$filepath2")"
使用 sed
,一种方法是将匹配项分组,然后 return 使用附加反斜杠的反向引用
sed 's/\([A-Za-z0-9\/][^\.]*\) /\ /g' input_file
/data-prod/bigdata/abc/test/1143-1003-004_1143-1003-905/static/common/images/header-background\ copy.jpg /mapped-data/data20/data3/header-background\ copy.jpg
使用参数替换拆分列:
while IFS= read -r line; do
# count raw tabs to validate format
tabs=${line//[!$'\t']}
tabs=${#tabs}
if ((tabs!=1)); then
echo "${line//$'\t'/TAB}: less or more than one raw tab, skipping…" >&2
else
# split by tab
source=${line%$'\t'*}
target=${line#*$'\t'}
rsync "$source" "$target"
fi
done < list.tsv
循环检查每一行是否只有一个制表符,如果没有则跳过。添加您的 rsync
选项等
确保列表没有符号转义字符(如 \t
或 \n
),或任何其他不属于文字文件名的 escapes/quotes。 tsv
和 csv
可以有各种不同的非文字引用,需要正确解析。
另请注意 rsync
的用法,用于将文件名从列表文件复制到单个目标:rsync [opts] —files-from="my-source-list" /my/target/