Can I use a variable in a file path in bash? If so, how?
Asked Answered
K

2

13

I'm trying to write a small shell script to find the most recently-added file in a directory and then move that file elsewhere. If I use:

ls -t ~/directory | head -1

and then store this in the variable VARIABLE_NAME, why can't I then then move this to ~/otherdirectory via:

mv ~/directory/$VARIABLE_NAME ~/otherdirectory

I've searched around here and Googled, but there doesn't seem to be any information on using variables in file paths? Is there a better way to do this?

Edit: Here's the portion of the script:

ls -t ~/downloads | head -1
read diags
mv ~/downloads/$diags ~/desktop/testfolder
Kyte answered 22/2, 2016 at 23:51 Comment(5)
Yes you can use variables in path. That isn't necessarily the issue you encountered. You may be encountering some issues such as expansion of ~. Or you may be having issue with file names and directory names containing space. I am not a mind reader so I wouldn't necessarily know what errors you got when you attempted it.Serology
What does $VARIABLE_NAME contain?Fritz
I've updated the post with the script portion that handles storing/moving the variable.Kyte
The portion of the script is unsufficient, as it does not show how VARIABLE_NAME receives its value. Moreover, it would be helpful if you described the observed effect: Did you get an error message, or did the file show up in a different place?Clermontferrand
The first portion of the script (not posted) creates a couple directories in /desktop and runs fine. When I get to the point where I'm moving the file, it seems like the script just hangs and nothing actually happens.Kyte
I
23

You can do the following in your script:

diags=$(ls -t ~/downloads | head -1)
mv ~/downloads/"$diags" ~/desktop/testfolder

In this case, diags is assigned the value of ls -t ~/downloads | head -1, which can be called on by mv.

Impurity answered 23/2, 2016 at 0:40 Comment(1)
Hey, thanks for this; ended up being the correct way to handle this after I figured out the subshell problem.Kyte
C
0

The following commands

ls -t ~/downloads | head -1
read diags

are probably not what you intend: the read command does not receive its input from the command before. Instead, it waits for input from stdin, which is why you believe the script to 'hang'. Maybe you wanted to do the following (at least this was my first erroneous attempt at providing a better solution):

ls -t ~/downloads | head -1 | read diags

However, this will (as mentioned by alvits) also not work, because each element of the pipe runs as a separate command: The variable diags therefore is not part of the parent shell, but of a subprocess.

The proper solution therefore is:

diags=$(ls -t ~/downloads | head -1)

There are, however, further possible problems, which would make the subsequent mv command fail:

  • The directory might be empty.
  • The file name might contain spaces, newlines etc.
Clermontferrand answered 23/2, 2016 at 0:17 Comment(5)
This piping has helped, but I seem to have transferred the entirety of the downloads directory into the testfolder now. It looks like $diags is being ignored by the mv command.Kyte
Try running bash in debug mode, that is with bash -x. You can also put the -x in the shebang line: #/bin/bash -xClermontferrand
@Kyte - This is a very well known issue with using variables within a sub-shell or pipes. The local variable $diags was assigned the output of ls -t ~/downloads | head -1, however, it was lost after the execution of the line. You should use printf -v diag '%s' $(ls -t ~/downloads | head -1).Serology
@Serology - Oops, certainly you are right, will fix that part of the answer.Clermontferrand
Thanks both of you! A friend showed me shellcheck.net and it saw the subshell issue right away, so I was able to figure this out. I ended up with diags=$(ls -t ~/downloads | head -1) and this was respected in mv -v ~/downloads/"$diags" ~/desktop/testfolderKyte

© 2022 - 2024 — McMap. All rights reserved.