在内联 shell 脚本中使用 read -r

在内联 shell 脚本中使用 read -r

我有一个文件,其中包含多个文件的绝对路径列表。我需要将文件中列出的所有文件移动到另一个目录。不幸的是,我必须使用内联 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

相关内容