Мой сценарий:
#!/bin/sh
_directory1="/home/user/test1"
_directory2="test2"
cd "${_directory1}/$_directory2"
for i in *
do
echo "$i"
done
А вот и ошибка:
./myscript.sh: 6: cd: can't cd to /home/user/test1/test2
Что я делаю не так?
решение1
Ваш исходный код до правок:
#!/bin/sh
_directory1="~/test1"
_directory2="test2"
for i in $(cd "${_directory1}/$_directory2")
do
echo "$i"
done
Тильда (
~
) не ведет себя как переменная. Например, она не будет расширяться до пути к вашему домашнему каталогу при использовании в кавычках. В скрипте используйте$HOME
вместо тильды.~
— это «ярлык», который вы можете использовать в командной строке, но$HOME
в скрипте он более описателен.- Видеть "Почему тильда (~) не раскрывается внутри двойных кавычек?" Чтобы получить больше информации.
cd
не выводит ничего, что можно было бы перебрать, поэтому использованиеcd
в подстановке команды сfor
не даст вам ничего хорошего. К сожалению, неясно, что именно вы хотите, чтобы делал ваш цикл, поэтому я не могу дать вам безошибочную альтернативную реализацию.
Код с вашими правками:
#!/bin/sh
_directory1="/home/user/test1"
_directory2="test2"
cd "${_directory1}/$_directory2"
for i in *
do
echo "$i"
done
Этот код выведет только
"./myscript.sh: 6: cd: can't cd to /test2"
если вы неправильно написали имя переменной _directory1
(и неправильно написанная переменная пуста, а /test2
каталог не существует).
Затем вы отредактировали сообщение об ошибке.сновасказать, что он выводит
./myscript.sh: 6: cd: can't cd to /home/user/test1/test2
что просто означает, что каталог /home/user/test1/test2
не существует. Вы не предоставили доказательств того, что этот каталогделаетсуществуют, поэтому нам придется поверить вашей системе на слово.
Вот скрипт, который выводит список содержимого каталога (предполагая, что каталог существует). Код выводит полный путь к каждому файлу.
#!/bin/bash
topdir=$HOME/test1
subdir=test2
printf '%s\n' "$topdir/$subdir"/*
Или,
#!/bin/bash
topdir=$HOME/test1
subdir=test2
shopt -s nullglob
for name in "$topdir/$subdir"/*; do
printf '%s\n' "$name"
done
Опция nullglob
оболочки делает так, что цикл вообще не запускается, если заданный шаблон ничему не соответствует. Без установки опции nullglob
шаблон останется неразвернутым, если он ничему не соответствует, и цикл будет использовать его в качестве значения для $name
в одной итерации.
Вы также можете установить dotglob
опцию оболочки ( shopt -s dotglob
), если вас интересуют скрытые имена (имена файлов, начинающиеся с .
символа).
Или, не печатая полный путь к каждому имени файла,
#!/bin/bash
topdir=$HOME/test1
subdir=test2
cd "$topdir/$subdir" || exit 1
printf '%s\n' *
exit 1
В случае сбоя скрипт будет прерван cd
.
Или,
#!/bin/bash
topdir=$HOME/test1
subdir=test2
cd "$topdir/$subdir" || exit 1
shopt -s nullglob
for name in *; do
printf '%s\n' "$name"
done
Чтобы напечатать только имена файлов без полного пути, не используя 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
Это использует basename
утилиту для извлечения только части имени файла из путей. Альтернатива в комментарии использует стандартную замену параметра, ${name##*/}
, для удаления начального пути каталога перед именами файлов (дословно «удалить самую длинную строку префикса, соответствующую шаблону */
из $name
»).