简体   繁体   English

Bash 文件名不会 append 从脚本文件

[英]Bash File names will not append to file from script

Hello I am trying to get all files with Jane's name to a separate file called oldFiles.txt.您好,我正在尝试将所有带有 Jane 名字的文件保存到一个名为 oldFiles.txt 的单独文件中。 In a directory called "data" I am reading from a list of file names from a file called list.txt, from which I put all the file names containing the name Jane into the files variable.在一个名为“data”的目录中,我正在从一个名为 list.txt 的文件中读取文件名列表,我从该文件中将包含名字 Jane 的所有文件名放入文件变量中。 Then I'm trying to test the files variable with the files in list.txt to ensure they are in the file system, then append the all the files containing jane to the oldFiles.txt file(which will be in the scripts directory), after it tests to make sure the item within the files variable passes.然后我尝试用 list.txt 中的文件测试文件变量以确保它们在文件系统中,然后 append 所有包含 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

The above code gets the desired files and displays them correctly, as well as creates the oldFiles.txt file, but when I open the file after running the script I find that nothing was appended to the file.上面的代码获取所需的文件并正确显示它们,并创建了 oldFiles.txt 文件,但是当我在运行脚本后打开文件时,我发现没有任何内容附加到文件中。 I tried changing the file assignment to a pointer instead files= grep " jane "../data/list.txt | cut -d' ' -f 3 ---> files=$(grep " jane "../data/list.txt)我尝试将文件分配改为指针files= grep " jane "../data/list.txt | cut -d' ' -f 3 ---> files=$(grep " jane "../data/list.txt) files= grep " jane "../data/list.txt | cut -d' ' -f 3 ---> files=$(grep " jane "../data/list.txt) to see if that would help by just capturing raw data to write to file, but then the error comes up "too many arguments on line 5" which is the 1st if test statement. files= grep " jane "../data/list.txt | cut -d' ' -f 3 ---> files=$(grep " jane "../data/list.txt)以查看仅捕获原始数据以写入文件是否有帮助,但随后出现错误向上“第 5 行太多 arguments”,这是第一个 if 测试语句。 The only way I get the script to work semi-properly is when I do ./findJane.sh > oldFiles.txt on the shell command line, which is me essentially manually creating the file.让脚本半正常工作的唯一方法是在 shell 命令行上执行./findJane.sh > oldFiles.txt ,这实际上是我手动创建文件。 How would I go about this so that I create oldFiles.txt and append to the oldFiles.txt all within the script?我将如何对此进行 go 以便我在脚本中创建 oldFiles.txt 和 append 到 oldFiles.txt?

As far as I can tell, this is what you're going for.据我所知,这就是你想要的。 This is totally a community effort based on the comments, catching your bugs.这完全是基于评论的社区努力,捕捉你的错误。 Obviously credit to Mark and Jetchisel for finding most of the issues.显然要归功于 Mark 和 Jetchisel 发现了大部分问题。 Notable changes:显着变化:

  • Fixed $files to use command substitution修复$files以使用命令替换
  • Fixed path to data/$file , assuming you have a directory at ~/data full of files data/$file的固定路径,假设你在~/data有一个充满文件的目录
  • Fixed the test to not test for a string of files, but just the single file (also using -f to make sure it's a regular file)修复了测试,不测试一串文件,而只测试单个文件(也使用-f来确保它是一个常规文件)
  • Using double brackets — you could also use double quotes instead, but you explicitly have a Bash shebang so there's no harm in using Bash syntax使用双括号——你也可以使用双引号代替,但你明确地有一个 Bash shebang 所以使用 Bash 语法没有坏处
  • Adding a second message about not matching files, because there are two possible cases there;添加关于不匹配文件的第二条消息,因为那里有两种可能的情况; you may need to adapt depending on the output you're looking for您可能需要根据您要查找的 output 进行调整
  • Removed the initial empty redirection — if you need to ensure that the file is clear before the rest of the script, then it should be added back, but if not, it's not doing any useful work删除了初始的空重定向——如果你需要确保文件在脚本的 rest 之前是清晰的,那么它应该被添加回来,但如果不是,它就没有做任何有用的工作
  • Changed the shebang to make sure you're using the user's preferred Bash, and added set -e because you should always add set -e更改了 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

The biggest problem you have is matching names like "jane" or "Jane's" , etc. while not matching "Janes" .你遇到的最大问题是匹配名称,如"jane""Jane's"等,而不匹配"Janes" grep provides the options -i (case insensitive match) and -w (whole-word match) which can tailor your search to what you appear to want without having to use the kludge ( " jane " ) of appending spaces before an after your search term. grep提供了选项-i (不区分大小写的匹配)和-w (全字匹配),它们可以根据您想要的内容定制您的搜索,而无需使用在搜索前后添加空格的笨拙( " jane " )学期。 (to properly do that you would use [[:space:]]jane[[:space:]] ) (要正确地做到这一点,你会使用[[:space:]]jane[[:space:]]

You also have the problem of what is your "script dir" if you call your script from a directory other than the one containing your script, such as calling your script from your $HOME directory with bash script/findJane.sh .如果您从包含脚本的目录以外的目录调用脚本,例如使用bash script/findJane.sh$HOME目录调用脚本,您还会遇到"script dir"是什么的问题。 In that case your script will attempt to append to $HOME/oldFiles.txt .在这种情况下,您的脚本将尝试 append 到$HOME/oldFiles.txt The positional parameter $0 always contains the full pathname to the current script being run, so you can capture the script directory no matter where you call the script from with:位置参数$0始终包含当前正在运行的脚本的完整路径名,因此无论您从何处调用脚本,都可以捕获脚本目录:

dirname "$0"

You are using bash, so store all the filenames resulting from your grep command in an array, not some general variable (especially since your use of " jane " suggests that your filenames contain whitespace)您正在使用 bash,因此将grep命令产生的所有文件名存储在一个数组中,而不是一些通用变量(特别是因为您使用" jane "表明您的文件名包含空格)

You can make your script much more flexible if you take the information of your input file (eg list.txt ), the term to search for (eg "jane" ), the location where to check for existence of the files (eg $HOME/data ) and the output filename to append the names to (eg "oldFile.txt" ) as command line [positonal] parameters.如果您获取输入文件的信息(例如list.txt )、要搜索的术语(例如"jane" )、检查文件是否存在的位置(例如$HOME/data )和 output 文件名到 append 名称(例如"oldFile.txt" )作为命令行 [positonal] 参数。 You can give each default values so it behaves as you currently desire without providing any arguments.您可以给每个默认值,使其按照您当前的期望运行,而无需提供任何 arguments。

Even with the additional scripting flexibility of taking the command line arguments, the script actually has fewer lines simply filling an array using mapfile (synonymous with readarray ) and then looping over the contents of the array.即使使用命令行 arguments 的额外脚本灵活性,脚本实际上有更少的行,只需使用mapfile (与readarray同义)填充数组,然后遍历数组的内容。 You also avoid the additional subshell for dirname with a simple parameter expansion and test whether the path component is empty -- to replace with '.'您还可以通过简单的参数扩展来避免dirname的附加子 shell,并测试路径组件是否为空——替换为'.' , up to you. , 由你决定。

If I've understood your goal correctly, you can put all the pieces together with:如果我正确理解了您的目标,您可以将所有部分放在一起:

#!/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 "%s\n" "${files[i]}" >> "$outfn"
done

(note: test expression and [ expression ] are synonymous, use what you like, though you may find [ expression ] a bit more readable) (注意: test expression[ expression ]是同义词,使用你喜欢的,尽管你可能会发现[ expression ]更具可读性)

(further note: "Janes" being plural is not considered the same as the singular -- adjust the grep expression as desired) (进一步注意: "Janes"作为复数并不被认为与单数相同——根据需要调整grep表达式)

Example Use/Output示例使用/输出

As was pointed out in the comment, without a sample of your input file, we cannot provide an exact test to confirm your desired behavior.正如评论中指出的那样,如果没有您的输入文件样本,我们无法提供准确的测试来确认您想要的行为。

Let me know if you have questions.如果您有任何疑问,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM