2017-02-27 98 views
0

我似乎有这个问题。这段代码在bash关联数组的脚本中第119行中断。我很抱歉的评论,但我对新的bash脚本很友善。这是代码:Bash关联数组错误

#!/bin/bash 
# Aliases file 

# Command usage: cpRecent/mvRecent -d {dirFrom},{dirTo} -n {numberofFiles} -e {editTheNames} 

# Error codes 
NO_ARGS="You need to pass in an argument" 
INVALID_OPTION="Invaild option:" 
NO_DIRECTORY="No directory found" 


# Return values 
fullpath= 
directories= 
numfiles= 
interactive= 

typeset -a files 
typeset -A filelist 

# Advise that you use relative paths 
__returnFullPath(){ 
    local npath 
    if [[ -d $1 ]]; then 
     cd "$(dirname $1)" 
     npath="$PWD/$(basename $1)" 
     npath="$npath/"   #Add a slash 
     npath="${npath%.*}"  #Delete . 
    fi 
    fullpath=${npath:=""} 
} 

__usage(){ 

wall <<End-Of-Message 
________________________________________________ 
<cpRecent/mvRecent> -d "<d1>,<d2>" -n <num> [-i] 
    -d First flag: Takes two arguments 
    -n Second flag: Takes one argument 
    -i Takes no arguments. Interactive mode 
    d1 Directory we are reading from  
    d2 Directory we are writing to 
    num Number of files 
________________________________________________ 
End-Of-Message 
} 


__processOptions(){ 
    while getopts ":d:n:i" opt; do 
     case $opt in 
      d) IFS=',' read -r -a directories <<< "$OPTARG";; 
      n) numfiles=$OPTARG;; 
      i) interactive=1;; 
      \?) echo "$INVALID_OPTION -$OPTARG" >&2 ; return 1;; 
      :) echo "$NO_ARGS"; __usage; return 1;; 
      *) __usage; return 1;; 
     esac 
    done    
} 


__getRecentFiles(){ 

    # Check some conditions 
    ((${#directories[@]} != 2)) && echo "$INVALID_OPTION Number of directories must be 2" && return 2 
    #echo ${directories[0]} ${directories[1]} 

    # Get the full paths of the directories to be read from/written to 
    __returnFullPath "${directories[0]}" 
    directories[0]="$fullpath" 
    __returnFullPath "${directories[1]}" 
    directories[1]="$fullpath" 

    if [[ -z ${directories[0]} || -z ${directories[1]} ]]; then 
     echo $NO_DIRECTORY 
     return 3 
    fi 

    [[ numfiles != *[!0-9]* ]] && echo "$INVALID_OPTION Number of files cannot be a string" && return 4 

    #numfiles=$(($numfiles + 0)) 
    (($numfiles == 0)) && echo "$INVALID_OPTION Number of files cannot be zero" && return 4 

    local num="-"$numfiles"" 

    # Get the requested files in directory(skips directories) 
    if [[ -n "$(ls -t ${directories[0]} | head $num)" ]]; then 
     # For some reason using local -a or declare -a does not seem to split the string into two 
     local tempfiles=($(ls -t ${directories[0]} | head $num)) 
     #IFS=' ' read -r -a tempfiles <<< "$string" 
     #echo ${tempfiles[@]} 
     for index in "${!tempfiles[@]}"; do 
      echo $index ${tempfiles[index]} 
      [[ -f "${directories[0]}${tempfiles[index]}" ]] && files+=("${tempfiles[index]}") 
     done 
    fi 

} 

#################################### 
# The problem is this piece of code 
__processLines(){ 
    local name 
    local answer 
    local dirFrom 
    local dirTo 
    if [[ -n $interactive ]]; then 
     for ((i=0; i< ${#files[@]}; i++)); do 
      name=${files[i]} 
      read -n 1 -p "Old name: $name. Do you wish to change the name(y/n)?" answer 
      [[ answer="y" ]] && read -p "Enter new name:" name 
      dirFrom="${directories[0]}${files[i]}" 
      dirTo="${directories[1]}$name" 
      fileslist["$dirFrom"]="$dirTo" 
     done 
    else          
     for line in $files; do 
      dirFrom="${directories[0]}$line" 
      echo $dirFrom # => /home/reclusiarch/Documents/test 
      dirTo="${directories[1]}$line" 
      echo $dirTo # => /home/reclusiarch/test 
      fileslist["$dirFrom"]="$dirTo" # This is the offending line 
     done  
    fi 

} 
########################################################### 

cpRecent(){ 
    __processOptions $* 
    __getRecentFiles 
    __processLines 
    for line in "${!filelist[@]}"; do 
     cp $line ${filelist[$line]} 
    done 
    echo "You have copied ${#fileList[@]} files" 
    unset files 
    unset filelist 
    return 
} 

mvRecent(){ 
    __processOptions $* 
    __getRecentFiles 
    __processLines 
    for line in "${!filelist[@]}"; do 
     mv $line ${filelist[$line]} 
    done 
    echo "You have copied ${#fileList[@]} files" 
    unset files 
    unset filelist 
    return 
} 

cpRecent "$*" 

我已经尝试了很多东西。要运行脚本,

$ bash -x ./testing.sh -d "Documents,." -n 2 

但似乎没有任何工作: 的错误是这样(使用bash的时候-x):

./testing.sh: line 119: /home/reclusiarch/Documents/test: syntax error: operand expected (error token is "/home/reclusiarch/Documents/test") 

如果我运行在命令行上的那款,它的工作原理:

$ typeset -A filelist 
$ filelist["/home/reclusiarch/Documents/test"]=/home/reclusiarch/test 
$ echo ${filelist["/home/reclusiarch/Documents/test"]} 
/home/reclusiarch/test 

感谢您的帮助!

编辑:我主要将脚本划分为一段有问题的代码,但可能会使其无法运行。再次,如果你想测试它,你可以运行给定的bash命令。 (理想情况下,脚本将驻留在用户的$ HOME目录中)。

编辑:解决(Charles Duffy解决了它)忘记哪个名字是一个简单的错误。

+2

您需要将其缩减为*最小*示例;你发布的大部分代码与你的问题无关。 – chepner

+0

你如何启动你的脚本,你可以放命令行吗?无论如何,@chepner是正确的,尽量减少到最低需要的表达! – OscarAkaElvis

+1

真的,'wall'显示使用信息?该系统的其他用户不会欣赏关于一个人如何滥用您的脚本。 – chepner

回答

0

你的宣言是:

typeset -A filelist 

但是,你使用是:

fileslist["$dirFrom"]="$dirTo" 

fileslistfilelist

+0

我觉得很愚蠢。我想我太累了,看不到它。达姆。感谢您的参与。顺便说一句,将“$ @”允许我使用getopt而不是“$ *”? – corax

+0

是的,但'getopt'实际上是不好的做法。请参阅[BashFAQ#35](http://mywiki.wooledge.org/BashFAQ/035)以获取可靠的替代方案。 –

+0

谢谢。现在查看链接。 – corax