Your original code before edits:
#!/bin/sh
_directory1="~/test1"
_directory2="test2"
for i in $(cd "${_directory1}/$_directory2")
do
echo "$i"
done
The tilde (~
) does not behave like a variable. It will, for example, not expand to the path to your home directory when used within quotes. In a script, use $HOME
instead of tilde. ~
is a "shortcut" that you may want to use on the command line, but $HOME
is more descriptive in a script.
cd
does not output anything that you can loop over, so using cd
in a command substitution with for
will not do you anything good. Unfortunately, it's unclear what you want your loop to actually do, so I can't give you a surefire alternative implementation.
The code with your edits:
#!/bin/sh
_directory1="/home/user/test1"
_directory2="test2"
cd "${_directory1}/$_directory2"
for i in *
do
echo "$i"
done
This code would only output
"./myscript.sh: 6: cd: can't cd to /test2"
if you misspell the name of the variable _directory1
(and the misspelled variable is empty, and the /test2
directory does not exist).
You then edited the error message again to say that it outputs
./myscript.sh: 6: cd: can't cd to /home/user/test1/test2
which simply means that the directory /home/user/test1/test2
does not exist. You have not given evidence that this directory does exist so we have to take your system's word for that.
Here's a script that lists the contents of a directory (assuming that the directory exists). The code prints the full pathname of each file.
#!/bin/bash
topdir=$HOME/test1
subdir=test2
printf '%s\n' "$topdir/$subdir"/*
Or,
#!/bin/bash
topdir=$HOME/test1
subdir=test2
shopt -s nullglob
for name in "$topdir/$subdir"/*; do
printf '%s\n' "$name"
done
The nullglob
shell option makes the loop not run at all if the given pattern does not match anything. Without setting the nullglob
option, the pattern would remain unexpanded if if didn't match anything, and the loop would use it as the value for $name
in a single iteration.
You may also want to set the dotglob
shell option (shopt -s dotglob
) if you are interested in hidden names (filenames starting with a .
character).
Or, without printing the full path to each filename,
#!/bin/bash
topdir=$HOME/test1
subdir=test2
cd "$topdir/$subdir" || exit 1
printf '%s\n' *
The exit 1
will terminate the script if the cd
fails.
Or,
#!/bin/bash
topdir=$HOME/test1
subdir=test2
cd "$topdir/$subdir" || exit 1
shopt -s nullglob
for name in *; do
printf '%s\n' "$name"
done
To print only the filenames without their full path, without using cd
:
#!/bin/bash
topdir=$HOME/test1
subdir=test2
shopt -s nullglob
for name in "$topdir/$subdir"/*; do
printf '%s\n' "$( basename "$name" )"
# or: printf '%s\n' "${name##*/}"
done
This uses the basename
utility to extract only the filename portion of the pathnames. The alternative in the comment uses a standard parameter substitution, ${name##*/}
, to delete the initial directory path before the filenames (literally "remove the longest prefix string matching the pattern */
from $name
").
cd
a specific directory. Then do afor
loop to see what's inside. – Mar 09 '20 at 21:35_directory1
variable's name. – Kusalananda Mar 09 '20 at 21:35for
do the job withoutcd
? – Mar 09 '20 at 21:51