1

I have a file that contains a list of absolute paths of several files. I need to move all of the files listed in the file to another directory. Unfortunately, I have to do this using in-line shell scripting (i.e. sh -c), and I have no power over text passed outside of the quotation marks of the script (I'm using a software that passes the command as an in-line shell script to the OS).

$file in the following command evaluates to an empty string when using in-line scripting.

sh -c "while IFS= read -r file; do mv $file /target_dir; done < /source_dir/list_of_files.txt"

But if I enter the command in the terminal, everything works fine:

while IFS= read -r file; do mv "$file" /target_dir; done < /source_dir/list_of_files.txt

Is it possible to use read in an in-line shell script? If so, what am I doing wrong? I would like to avoid using bash file if possible, but I may not have that option.

OS:RedHat 8.7

list_of_files.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

3 Answers3

1

I guess the $file variable you pass to sh is interpreted outside the sh context. You should try to escape the dollar sign : \$file. You can also add escaped quotes around \" to deal with filename containing spaces.

The final command would look like :

sh -c "while IFS= read -r file; do mv \"\$file\" /target_dir; done < /source_dir/list_of_files.txt"
Saïmonn
  • 426
0
$ bash -c "while IFS= read -r file; do echo mv .$file. /target_dir; done < /source_dir/list_of_files.txt"

The "-quotes allows $file to be evaluated as you hit ENTER, taking the null or existing value in your CURRENT shell as literal text, replacing $file with either that value or "" (the null string).

$ bash -c 'while IFS= read -r file; do echo mv "$file" /target_dir; done < "/source_dir/list_of_files.txt"'

Does not allow evaluation of $variable as you press ENTER, and thus leaves the TEXT $file as is, in place, until your one-liner is executing.

I assume you have a reason to use sh - if not, beware that sh often is a link to bash or something else (making it mimick sh)

Ubuntu 20.04:

$ ls -l `which sh`
lrwxrwxrwx 1 root root 4 mar 11  2021 /usr/bin/sh -> dash
Hannu
  • 10,568
0

The problem is not with read, the problem is with your incorrect use of quotes around $file.

  • In the working example, when you use mv "$file" ..., the variable inside double-quotes is expanded at the moment 'mv' is run.

  • Very similarly, in the non-working example where you use sh -c "... mv $file ...", the variable is expanded at the moment 'sh' is run. The resulting script is therefore not mv $file /target_dir but mv /target_dir, with nothing left for expansion at that point.

To avoid this, either use single quotes for the parameter or use \$ to prevent expansion:

  • sh -c '... mv $file ...'
  • sh -c "... mv \$file ..."

...and also bring back the double-quotes around "$file" inside the script – you still want to have them:

  • sh -c '... mv "$file" ...'
  • sh -c "... mv \"\$file\" ..."
grawity
  • 501,077