我的腳本:
#!/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
在命令替換中使用 withfor
不會為您帶來任何好處。不幸的是,目前還不清楚您希望循環實際執行什麼操作,因此我無法為您提供可靠的替代實作。
包含您編輯的程式碼:
#!/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
如果給定的模式與任何內容都不匹配, shellnullglob
選項將使循環根本不運行。如果不設定該nullglob
選項,如果 if 不符合任何內容,則模式將保持未展開狀態,並且循環將$name
在單次迭代中使用它作為 for 的值。
如果您對隱藏名稱(以字元開頭的檔案名稱)感興趣,您可能還需要設定dotglob
shell 選項 ( )。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