rm 带有文件名数组

问题描述 投票:0回答:1

我正在制作一个高级删除脚本。这个想法是用户输入一个 grep 正则表达式来查找需要删除的内容,然后脚本对所有内容执行 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”之前传递了打印出来的整个字符串,它就可以正常工作。但是当我用数组执行此操作时,它失败了。

我做错了什么?

arrays bash
1个回答
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
    必须显式创建为数组才能真正 be 一个数组 - 否则,它只是一个包含一堆文件的字符串。

    这是一个数组:

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

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

    files='"first file" "second file"'
    
  • 正确的 bash 数组可以使用

    "${arrayname[@]}"
    展开以获取所有内容,或者使用
    "$arrayname"
    来仅获取第一个条目。

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

    ...因此检查数组中 first 条目是否存在(无论是作为文件还是符号链接)——这足以判断 glob 表达式是否确实扩展,或者是否不匹配任何内容。

  • 布尔值比包含

    true
    false
    的字符串更好地用数值表示:如果
    if $valid
    的内容可以设置为用户控制的值,则运行
    valid
    有可能执行任意活动,而
    if (( valid ))
    ——检查
    $valid
    是否为正数值(true)或其他值(false)——在其他地方存在错误时产生副作用的空间要小得多。

  • 无需循环遍历数组条目即可将它们打印在列表中:只要参数(来自数组扩展)多于其格式字符串所需的参数,

    printf "$format_string" "${array[@]}"
    就会额外扩展格式字符串。此外,在格式字符串中使用
    %q
    将引用不可打印的值、空格、换行符等。采用人类读者和 shell 都可以使用的格式——否则使用
    touch $'evil\n  - hiding'
    创建的文件将显示为两个列表条目,而实际上它只有一个。

© www.soinside.com 2019 - 2024. All rights reserved.