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 Answers 3

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"
1
  • ... which has the "same effect" as replacing the quotes from " to ' (double to single), with the difference that any quotes inside the string doesn't need to be escaped when using '. Commented Mar 1, 2023 at 17:27
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\" ..."
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
3
  • More on bash, www.tldp.org, Bash guides - old but still valid. Commented Feb 28, 2023 at 16:34
  • Unfortunately the use of sh is out of my control. It's being called by the software I'm using :/. Thanks for the tip. Commented Feb 28, 2023 at 20:39
  • The use of sh is up to each and everyone; just trying to tell that there might be one or two subtle or unexpected differences. Commented Mar 1, 2023 at 17:32

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.