Bash 文件名不会从脚本追加到文件



您好,我正在尝试将所有带有 Jane 名称的文件放入一个名为 oldFiles.txt 的单独文件中。 在一个名为"data"的目录中,我正在从一个名为 list.txt 的文件中读取文件名列表,我将包含名称 Jane 的所有文件名放入 files 变量中。 然后我尝试使用列表中的文件测试 files 变量.txt以确保它们在文件系统中,然后将包含 jane 的所有文件附加到 oldFiles.txt 文件(它将在脚本目录中),在它测试以确保文件变量中的项目通过之后。

#!/bin/bash
> oldFiles.txt
files= grep " jane " ../data/list.txt | cut -d' ' -f 3
if test -e ~data/$files; then
for file in $files; do
if test -e ~/scripts/$file; then
echo $file>> oldFiles.txt
else
echo "no files"
fi
done
fi

上面的代码获取所需的文件并正确显示它们,并创建oldFiles.txt文件,但是当我在运行脚本后打开文件时,我发现该文件没有附加任何内容。我尝试将文件分配更改为指针,而不是files= grep " jane " ../data/list.txt | cut -d' ' -f 3 ---> files=$(grep " jane " ../data/list.txt)看看这是否有助于捕获原始数据以写入文件,但随后出现错误"第 5 行上的参数太多",这是第一个 if 测试语句。我让脚本半正常工作的唯一方法是当我在 shell 命令行上执行./findJane.sh>oldFiles.txt时,这基本上是我手动创建文件。我将如何做到这一点,以便我在脚本中创建旧文件.txt并附加到旧文件.txt所有这些都在脚本中?

您遇到的最大问题是匹配"jane""Jane's"等名称,而不匹配"Janes"grep提供了-i(不区分大小写的匹配)和-w(全字匹配)的选项,这些选项可以根据您想要的内容定制您的搜索,而不必在搜索词之前附加空格(" jane ")。(要正确执行此操作,您将使用[[:space:]]jane[[:space:]])

如果您从包含脚本的目录以外的目录调用脚本,例如使用bash script/findJane.sh$HOME目录调用脚本,您还会遇到"script dir"是什么的问题。在这种情况下,您的脚本将尝试追加到$HOME/oldFiles.txt。positional 参数$0始终包含当前正在运行的脚本的完整路径名,因此无论您从何处调用脚本,都可以捕获脚本目录:

dirname "$0"

您正在使用 bash,因此将grep命令产生的所有文件名存储在数组中,而不是一些通用变量(特别是因为您使用" jane "表明您的文件名包含空格)

如果你获取输入文件的信息(例如list.txt),你可以使你的脚本更加灵活,搜索的术语(例如"jane"),检查文件是否存在的位置(例如$HOME/data) 和输出文件名以将名称附加到(例如"oldFile.txt") 作为命令行 [正置] 参数。您可以为每个默认值指定,使其按照您当前的意愿运行,而无需提供任何参数。

即使具有采用命令行参数的额外脚本灵活性,脚本实际上也具有更少的行数,只需使用mapfile(与readarray同义)填充数组,然后循环遍历数组的内容。您还可以通过简单的参数扩展来避免额外的子外壳dirname,并测试路径组件是否为空 - 替换为'.',由您决定。

如果我正确理解了您的目标,您可以将所有部分放在一起:

#!/bin/bash
# positional parameters
src="${1:-../data/list.txt}"  # 1st param - input (default: ../data/list.txt)
term="${2:-jane}"             # 2nd param - search term (default: jane)
data="${3:-$HOME/data}"       # 3rd param - file location (defaut: ../data)
outfn="${4:-oldFiles.txt}"    # 4th param - output (default: oldFiles.txt)
# save the path to the current script in script
script="$(dirname "$0")"
# if outfn not given, prepend path to script to outfn to output
# in script directory (if script called from elsewhere)
[ -z "$4" ] && outfn="$script/$outfn"
# split names w/term into array
# using the -iw option for case-insensitive whole-word match
mapfile -t files < <(grep -iw "$term" "$src" | cut -d' ' -f 3)
# loop over files array
for ((i=0; i<${#files[@]}; i++)); do
# test existence of file in data directory, redirect name to outfn
[ -e "$data/${files[i]}" ] && printf "%sn" "${files[i]}" >> "$outfn"
done

(注意:test expression[ expression ]是同义词,请使用您喜欢的内容,尽管您可能会发现[ expression ]更具可读性)

(进一步说明:"Janes"复数不被视为与单数相同 - 根据需要调整grep表达式)

示例使用/输出

正如评论中指出的那样,如果没有输入文件的示例,我们无法提供精确的测试来确认您想要的行为。

如果您有任何疑问,请告诉我。

据我所知,这就是你要做的。这完全是基于评论的社区努力,捕获您的错误。显然,这要归功于马克和杰奇塞尔发现了大部分问题。值得注意的变化:

  • 修复了使用命令替换$files
  • 修复了data/$file的路径,假设你有一个~/data满文件的目录
  • 修复了测试不测试一串文件,而只测试单个文件(也使用-f来确保它是常规文件)
  • 使用双括号 - 你也可以使用双引号代替,但你明确有一个Bash shebang,所以使用Bash语法没有坏处
  • 添加有关不匹配文件的第二条消息,因为那里有两种可能的情况;您可能需要根据要查找的输出进行调整
  • 删除了最初的空重定向 — 如果您需要确保文件在脚本的其余部分之前是清晰的,那么它应该被添加回来,但如果不是,它不会做任何有用的工作
  • 更改了 shebang 以确保您使用的是用户首选的 Bash,并添加了set -e因为您应该始终添加set -e
#!/usr/bin/env bash
set -e
files=$(grep " jane " ../data/list.txt | cut -d' ' -f 3)
for file in $files; do
if [[ -f $HOME/data/$file ]]; then
if [[ -f $HOME/scripts/$file ]]; then
echo "$file" >> oldFiles.txt
else
echo "no matching file"
fi
else
echo "no files"
fi
done

最新更新