我有一个文件,其中包含多个文件的绝对路径列表。我需要将文件中列出的所有文件移动到另一个目录。不幸的是,我必须使用内联 shell 脚本(即 sh -c)来执行此操作,并且我无法控制脚本引号之外的文本(我正在使用将命令作为内联 shell 脚本传递给操作系统的软件)。
当使用内联脚本时,以下命令中的 $file 计算结果为空字符串。
sh -c "while IFS= read -r file; do mv $file /target_dir; done < /source_dir/list_of_files.txt"
但如果我在终端中输入命令,一切都正常:
while IFS= read -r file; do mv "$file" /target_dir; done < /source_dir/list_of_files.txt
是否可以在内联 shell 脚本中使用 read?如果可以,我做错了什么?如果可能的话,我想避免使用 bash file,但我可能没有这个选择。
操作系统:RedHat 8.7
文件列表.txt
/home/usr1/file-16952.txt
/home/usr1/file-1825.txt
/home/usr1/file-2055.txt
/home/usr1/file-2165.txt
/home/usr1/file-2224.txt
/home/usr1/file-2452.txt
/home/usr1/file-4565.txt
/home/usr1/file-5763.txt
/home/usr1/file-8361.txt
答案1
我猜$file
你传递给的变量sh
是在sh
上下文之外解释的。你应该尝试转义美元符号 : \$file
。你还可以在周围添加转义引号\"
来处理包含空格的文件名。
最终的命令如下:
sh -c "while IFS= read -r file; do mv \"\$file\" /target_dir; done < /source_dir/list_of_files.txt"
答案2
问题不在于read
,问题在于您对 周围的引号的使用不正确$file
。
在工作示例中,当您使用时
mv "$file" ...
,双引号内的变量在运行“mv”时会扩展。非常相似,在您使用的非工作示例中
sh -c "... mv $file ..."
,变量被扩展此刻‘sh’正在运行。因此,最终的脚本不是mv $file /target_dir
,但是mv /target_dir
,此时没有任何可供扩展的内容。
为了避免这种情况,请对参数使用单引号或使用\$
以防止扩展:
sh -c '... mv $file ...'
sh -c "... mv \$file ..."
...并重新添加双引号"$file"
里面脚本——你仍然希望拥有它们:
sh -c '... mv "$file" ...'
sh -c "... mv \"\$file\" ..."
答案3
$ bash -c "while IFS= read -r file; do echo mv .$file. /target_dir; done < /source_dir/list_of_files.txt"
当您按下 ENTER 键时, -quotes"
允许$file
进行评估,将当前 shell 中的空值或现有值作为文字文本,并$file
用该值或""
(空字符串)替换。
$ bash -c 'while IFS= read -r file; do echo mv "$file" /target_dir; done < "/source_dir/list_of_files.txt"'
不允许$variable
在您按下 ENTER 键时进行评估,因此将 TEXT 保留$file
原样,直到执行单行命令为止。
我认为您有理由使用sh
- 如果没有,请注意,sh
通常是指向bash
或其他东西的链接(使其模仿sh
)
Ubuntu 20.04:
$ ls -l `which sh`
lrwxrwxrwx 1 root root 4 mar 11 2021 /usr/bin/sh -> dash