Bash:带有一系列文件名的文件

时间:2016-05-09 15:45:17

标签: arrays bash

所以我正在制作一个高级删除脚本。想法是用户为需要删除的内容输入grep regex,脚本对所有内容执行rm操作。基本上不需要每次都直接在命令行中编写所有代码。

到目前为止,这是我的脚本:

#!/bin/bash
# Script to delete files passed to it

if [ $# -ne 1 ]; then
    echo "Error! Script needs to be run with a single argument that is the regex for the files to delete"
    exit 1
fi

IFS=$'\n'

files=$(ls -a | grep $1 | awk '{print "\"" $0 "\"" }')

## TODO ensure directory support

echo "This script will delete the following files:"
for f in $files; do
    echo "  $f"
done

valid=false

while ! $valid ; do
    read -p "Do you want to proceed? (y/n): "
    case $REPLY in
        y)
            valid=true
            echo "Deleting, please wait"
            echo $files
            rm ${files}
        ;;
        n)
            valid=true
        ;;
        *)
            echo "Invalid input, please try again"
        ;;
    esac
done

exit 0

我的问题是当我实际执行“rm”操作时。我不断收到错误,说没有这样的文件或目录。

这是我正在使用的目录:

drwxr-xr-x   6 user  staff   204 May  9 11:39 .
drwx------+ 51 user  staff  1734 May  9 09:38 ..
-rw-r--r--   1 user  staff    10 May  9 11:39 temp two.txt
-rw-r--r--   1 user  staff     6 May  9 11:38 temp1.txt
-rw-r--r--   1 user  staff     6 May  9 11:38 temp2.txt
-rw-r--r--   1 user  staff    10 May  9 11:38 temp3.txt

我正在调用这样的脚本:easydelete.sh'^ tem'

这是输出:

This script will delete the following files:
  "temp two.txt"
  "temp1.txt"
  "temp2.txt"
  "temp3.txt"
Do you want to proceed? (y/n): y
Deleting, please wait
"temp two.txt" "temp1.txt" "temp2.txt" "temp3.txt"
rm: "temp two.txt": No such file or directory
rm: "temp1.txt": No such file or directory
rm: "temp2.txt": No such file or directory
rm: "temp3.txt": No such file or directory

如果我尝试直接删除其中一个文件,它可以正常工作。如果我甚至在调用“rm”之前传递了打印出的整个字符串,它就可以正常工作。但是当我使用数组时,它会失败。

我知道我正在处理数组错误,只是不确定我做错了什么。任何帮助,将不胜感激。感谢。

1 个答案:

答案 0 :(得分:3)

改为考虑:

# put all filenames containing $1 as literal text in an array
#files=( *"$1"* )

# ...or, use a grep with GNU extensions to filter contents into an array:
# this passes filenames around with NUL delimiters for safety
#files=( )
#while IFS= read -r -d '' f; do
#  files+=( "$f" )
#done < <(printf '%s\0' * | egrep --null --null-data -e "$1")

# ...or, evaluate all files against $1, as regex, and add them to the array if they match:
files=( )
for f in *; do
  [[ $f =~ $1 ]] && files+=( "$f" )
done

# check that the first entry in that array actually exists
[[ -e $files || -L $files ]] || {
  echo "No files containing $1 found; exiting" >&2
  exit 1
}

# warn the user
echo "This script will delete the following files:" >&2
printf '  %q\n' "${files[@]}" >&2

# prompt the user
valid=0
while (( ! valid )); do
  read -p "Do you want to proceed? (y/n): "
  case $REPLY in
    y) valid=1; echo "Deleting; please wait" >&2; rm -f "${files[@]}" ;;
    n) valid=1 ;;
  esac
done

我将在下面详细介绍:

  • files必须明确地创建为一个实际数组的数组 - 否则,它只是一个包含大量文件的字符串。

    这是一个数组:

    files=( "first file" "second file" )
    

    这不是一个数组(实际上,可能是单个文件名):

    files='"first file" "second file"'
    
  • 使用"${arrayname[@]}"展开正确的bash数组以获取所有内容,或"$arrayname"仅获取第一个条目。

    [[ -e $files || -L $files ]]
    

    ...因此检查数组中第一个条目的存在(无论是文件还是符号链接) - 这足以判断glob表达式是否实际上是扩展的,或者如果它什么都不匹配。

  • 布尔值更好地用数字值表示,而不是包含truefalse的字符串:如果if $valid的内容,则运行valid有可能执行任意活动可以设置为用户控制的值,而if (( valid )) - 检查$valid是否为正数值(true)或其他(false) - 的副作用空间小得多其他地方存在漏洞。

  • 没有必要循环遍历数组条目以在列表中打印它们:printf "$format_string" "${array[@]}"只要有更多的参数(来自数组扩展)而不是格式字符串需要,就会扩展格式字符串。此外,在格式字符串中使用%q将引用非打印值,空格,换行符和&amp; c。用于人类读者和shell都可以使用的格式 - 否则用touch $'evil\n - hiding'创建的文件似乎是两个列表条目,而实际上只有一个。