0

How do you use a command line argument as a file path and check for file existence in Bash?

I have the simple Bash script test.sh:

#!/bin/bash

set -e
echo "arg1=$1"
if [ ! -f "$1" ]
then
    echo "File $1 does not exist."
    exit 1
fi
echo "File exists!"

and in the same directory, I have a data folder containing stuff.txt.

If I run ./test.sh data/stuff.txt I see the expected output:

arg1=data/stuff.txt
"File exists!"

However, if I call this script from a second script test2.sh, in the same directory, like:

#!/bin/bash
fn="data/stuff.txt"
./test.sh $fn

I get the mangled output:

arg1=data/stuff.txt
 does not exist

Why does the call work when I run it manually from a terminal, but not when I run it through another Bash script, even though both are receiving the same file path? What am I doing wrong?

Edit: The filename does not have spaces. Both scripts are executable. I'm running this on Ubuntu 18.04.

Cerin
  • 60,957
  • 96
  • 316
  • 522
  • 1
    So long as `fn` does NOT contain whitespace, you should be okay, but it would more properly be called as `./test.sh "$fn"`. – David C. Rankin Sep 18 '19 at 03:54
  • Of course, if `./test.sh` is not executable (e.g. `chmod +x test.sh`), then it will not do anything and you will get funny output (like permission denied). Without making it executable, you would need `bash ./test.sh "$fn"`. (otherwise, there is nothing wrong with what you are doing) – David C. Rankin Sep 18 '19 at 04:14
  • add some debugging statements like `echo "\$@=[$@]"; echo "PWD=$PWD"`. I'm betting your `PWD` changes between your two invocation methods. You can also test with a fully qualified path to file, i.e. `/home/userName/data/File.txt` (note the initial `/` char. ). Good luck. – shellter Sep 18 '19 at 04:49
  • 1
    It looks to me like your second script has DOS/Windows-style line endings, which causes all sorts of weird problems. See: [Are shell scripts sensitive to encoding and line endings?](https://stackoverflow.com/questions/39527571/are-shell-scripts-sensitive-to-encoding-and-line-endings) – Gordon Davisson Sep 18 '19 at 05:12
  • This is weird, because in my PC your code works well. Just for your info, I used bash terminal. – YONGSOO KIM Sep 18 '19 at 05:25
  • 1
    agree with @GordonDavisson , the output of second script " does not exist" is weird comparing with first script , and likely caused by unexpected ```\r``` – James Li Sep 18 '19 at 06:45
  • @bigdataolddriver An extra whitespace character was my suspicion too. I also noticed that the path is 14 characters, but if I print out the length of `$1` inside `test.sh`, it says it's 15. Where is that extra character coming from and how do I remove it? If there is an extra `\r` character in it, why does the filename print out correctly as arg1 echo line? – Cerin Sep 18 '19 at 13:59
  • the ```\r``` affects every char appears between itself and next ```\n``` . use ```vim -b test2.sh``` to see if there is any ```^M``` showing up in vim, or use ```od -c test2.sh``` dump to console, you would see ```\r``` printed if there is one. – James Li Sep 18 '19 at 14:38

1 Answers1

0

The filename was getting an extra whitespace character added to it as a result of how I was retrieving it in my second script. I didn't note this in my question, but I was retrieving the filename from folder list over SSH, like:

fn=$(ssh -t "cd /project/; ls -t data | head -n1" | head -n1)

Essentially, I wanted to get the filename of the most recent file in a directory on a remote server. Apparently, head includes the trailing newline character. I fixed it by changing it to:

fn=$(ssh -t "cd /project/; ls -t data | head -n1" | head -n1 | tr -d '\n' | tr -d '\r')

Thanks to @bigdataolddriver for hinting at the problem likely being an extra character.

Cerin
  • 60,957
  • 96
  • 316
  • 522