[英]How to properly process and print files with spaces in bash
我正在用bash編寫一個簡單的遞歸ls程序(我很沒經驗過,所以請隨意保持殘酷)。
該程序應該在一個單獨的行上打印出每個文件(可能是目錄),每次輸入一個新目錄時,輸出都會移過4個空格,以給它一個樹狀的輸出。
目前,它不會正確打印帶有空格的文件,並且它不會在目錄之后放置正斜杠。 (更多細節如下。)
recls () {
# store current working directory
# issues: seems bad to have cwd defined up here and used down below in getAbsolutePath -- too much coupling
cwd=$PWD
# get absolute path of arg
argdir=`getAbsolutePath "$@"`
# check if it exists
if [ ! -e $argdir ]; then
echo "$argdir does not exist"
return 1
fi
echo "$argdir exists"
# check if it's a directory
if [ ! -d $argdir ]; then
echo "$argdir is not a directory"
return 2
fi
echo "$argdir is a directory"
tab=""
recls_internal $argdir
return 0
}
recls_internal () {
for file in $@; do
echo -n "$tab${file##/*/}"
if [ -d $file ]; then
# print forward slash to show it's a directory
echo "/"
savedtab=$tab
tab="$tab "
myls_internal $file/*
tab=$savedtab
else
# if not a directory, print a new line
echo ""
fi
done
}
getAbsolutePath () {
if [ -z ${1##/*} ]; then
echo "$1"
else
echo "$cwd/$1"
fi
}
該腳本包含在名為bash-practice
的文件夾中。 當我recls .
,我得到以下輸出:
./
myls.sh
myls.sh~
recdir.sh
recls.sh
recls.sh~
sample
document.txt
sample-folder
sample-stuff
test-12.txt
test-1.txt
test-2.txt
sort-test.txt
sort-text-copy.txt
test-5-19-14-1
如您所見,縮進工作正常但有兩個問題:
1)文件sample document.txt
分布在兩行中,因為它有一個空格。
2)每個目錄前面都應該有一個正斜杠,但由於某種原因,只能在第一個目錄上運行。
為了修復(1),我嘗試保存內部文件分隔符並用換行符替換它,如下所示:
...
tab=""
savedIFS=$IFS
IFS="\n"
recls_internal $argdir
IFS=$savedIFS
return 0
但這根本不起作用。 它甚至沒有顯示超過第一個文件夾。 顯然,我對事物的理解是不正確的。
至於(2),我認為沒有任何理由不應該按預期工作。
bash對我來說很難,因為它似乎比大多數其他編程語言(作為shell腳本語言)具有更多不尋常的語法,所以我將非常感謝我對錯誤的任何見解,以及解決方案。
我去了mklement0建議的網站http://www.shellcheck.com ,它的提示基本上都是雙引號。 當我雙引號"$@"
,程序正確打印文件sample document.txt
,但之后直接打印出來,它給了我一個“ binary operator expected
”錯誤。 這是現在的樣子打印出來的:
好吧,事實證明我有一個拼寫錯誤導致它在遞歸時默認為我的函數的早期版本myls_internal
。 此早期版本未使用正斜杠標記目錄。 “更新”部分中的錯誤消息也已修復。 我換了線
myls_internal "$file/*"
至
recls_internal $file/*
現在它似乎正常工作。 如果有人正在寫答案,我仍然感謝你的見解,因為我並不真正理解引用“$ @”修復間距問題的機制。
固定代碼:
recls () {
# store current working directory
# issues: seems bad to have cwd defined up here and used down below in getAbsolutePath -- too much coupling
cwd=$PWD
# get absolute path of arg
argdir=$(getAbsolutePath "$@")
# check if it exists
if [ ! -e $argdir ]; then
echo "$argdir does not exist"
return 1
fi
echo "$argdir exists"
# check if it's a directory
if [ ! -d $argdir ]; then
echo "$argdir is not a directory"
return 2
fi
echo "$argdir is a directory"
tab=""
recls_internal $argdir
return 0
}
recls_internal () {
for file in "$@"; do
echo -n "$tab${file##/*/}"
if [ -d "$file" ]; then
# print forward slash to show it's a directory
echo "/"
savedtab=$tab
tab="$tab "
recls_internal $file/*
tab=$savedtab
else
# if not a directory, print a new line
echo ""
fi
done
}
getAbsolutePath () {
if [ -z ${1##/*} ]; then
echo "$1"
else
echo "$cwd/$1"
fi
}
固定輸出:
這條線
recls_internal $file/*
應該是
recls_internal "$file"/*
它正確處理帶有空格的目錄。 否則,包含Homework1.pdf
和Homework2.pdf
的文件夾(如cs 350
將擴展為
cs 350/Homework1.pdf 350/Homework2.pdf
什么時候應該
cs 350/Homework1.pdf cs 350/Homework2.pdf
我認為? 我並沒有真正了解正在發生的事情的細節,但這似乎解決了這個問題。
為了說明"$@"
和$@
之間的區別,讓我們考慮以下兩個函數:
f() { for i in $@; do echo $i; done; }
g() { for i in "$@"; do echo $i; done; }
當使用參數a "bc" "de"
調用這些函數時,結果將是
fa "bc" "de" abcde
ga "bc" "de" abcde
因此,當“$ @”在雙引號內時,擴展會將每個參數保存在單獨的單詞中(即使參數包含一個或多個空格)。 當擴展$ @(不帶雙引號)時,帶空格的參數將被視為兩個單詞。
在您的腳本中,您還需要用雙引號括起argdir
和file
。 當目錄或文件的名稱包含空格時,它很有用,因此名稱將被視為單個值。 修改腳本下方。
#! /bin/bash -u
recls () {
# store current working directory
# issues: seems bad to have cwd defined up here and used down below in getAbsolutePath -- too much coupling
cwd=$PWD
# get absolute path of arg
argdir=`getAbsolutePath "$@"`
# check if it exists
if [ ! -e "$argdir" ]; then
echo "$argdir does not exist"
return 1
fi
echo "$argdir exists"
# check if it's a directory
if [ ! -d "$argdir" ]; then
echo "$argdir is not a directory"
return 2
fi
echo "$argdir is a directory"
tab=""
recls_internal "$argdir"
return 0
}
recls_internal () {
for file in "$@"; do
echo -n "$tab${file##/*/}"
if [ -d "$file" ]; then
# print forward slash to show it's a directory
echo "/"
savedtab=$tab
tab="$tab "
recls_internal "$file"/*
tab=$savedtab
else
# if not a directory, print a new line
echo ""
fi
done
}
getAbsolutePath () {
if [ -z ${1##/*} ]; then
echo "$1"
else
echo "$cwd/$1"
fi
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.