簡體   English   中英

如何在bash中正確處理和打印帶空格的文件

[英]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腳本語言)具有更多不尋常的語法,所以我將非常感謝我對錯誤的任何見解,以及解決方案。

更新#1

我去了mklement0建議的網站http://www.shellcheck.com ,它的提示基本上都是雙引號。 當我雙引號"$@" ,程序正確打印文件sample document.txt ,但之后直接打印出來,它給了我一個“ binary operator expected ”錯誤。 這是現在的樣子打印出來的:

在此輸入圖像描述

更新#2 [問題解決了嗎?]

好吧,事實證明我有一個拼寫錯誤導致它在遞歸時默認為我的函數的早期版本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

}

固定輸出:

在此輸入圖像描述

更新#3

這條線

recls_internal $file/*

應該是

recls_internal "$file"/*

它正確處理帶有空格的目錄。 否則,包含Homework1.pdfHomework2.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

  • function g ga "bc" "de" abcde

因此,當“$ @”在雙引號內時,擴展會將每個參數保存在單獨的單詞中(即使參數包含一個或多個空格)。 當擴展$ @(不帶雙引號)時,帶空格的參數將被視為兩個單詞。

在您的腳本中,您還需要用雙引號括起argdirfile 當目錄或文件的名稱包含空格時,它很有用,因此名稱將被視為單個值。 修改腳本下方。

#! /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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM