【问题标题】:How do you format output string in bash script for input by another script?如何格式化 bash 脚本中的输出字符串以供另一个脚本输入?
【发布时间】:2014-04-05 00:59:21
【问题描述】:

我需要解压缩一堆学生作业 (jar) 文件,以便我可以使用脚本将内容提交到 Moss (Stanford) 抄袭检测服务器。我在 Java 中做了同样的事情,这很简单,但我正在尝试重新实现为 bash 脚本。

我正在尝试执行以下操作:

  1. 获取学生姓名列表(每个学生都有一个目录)。
  2. 在每个学生目录中,存在从 1 到 最新提交。我需要获取最高的目录 数字。
  3. 在每个提交目录中都包含一个 我需要的jar文件。我将每个 jar 复制到一个临时目录中 与学生同名并解压缩。
  4. 我需要将临时目录列表格式化为表单中的字符串

    /tempDir/studentName1/.languageExt /tempDir/studentName2/.languageExt

学生目录具有基本结构:

Student_Root_Directory: 
Student1 
Student2 
    Student1
        Sub-Directories: 1 2 3 4 5 
        1: student1.jar
        2: student1.jar
        ...
    Student2
        Sub-Directories: 1 2 3
        1. student2.jar
        ...

要执行上面的前 3 个步骤:

#!/bin/bash
# Extract all jar files into a temp directory called /home/moss/tempJarFiles/studentName
# $1 is the command line argument that contains the path to the institution submission dir.
# $2 is the language extension: .c, .cpp, .java, .py

students=`ls $1`
student_dir=$1
languageExt=$2
mossDir="/home/moss"
tempDir="/home/moss/tempJarStorage"
for student in $students
        do
        latestSubmissionDir=`ls -t $student_dir/$student | head -1`
        for jarDir in $latestSubmissionDir
                do
                mkdir $tempDir/$student
                cp $student_dir/$student/$jarDir/*.jar $tempDir/$student
                unzip -d $tempDir/$student/ -o -j $tempDir/$student/$student.jar *.$languageExt
                rm $tempDir/$student/$student.jar
                done
        done

...这导致在一个临时目录中创建了许多学生目录,该目录仅包含学生提交的解压缩内容。 我需要将新临时目录的 ls 输出格式化为包含以下内容的字符串:

/tempDir/studentName1/\*.languageExt /tempDir/studentName2/\*.languageExt

我已经尝试过

find "$tempDir" -iname "*.$languageExt" -printf "%p/*.$languageExt"

使用 iname 而不是 - 但我要么有包含额外目录信息的输出,例如 $tempDir/*.languageExt(当我只需要子目录 $tempDir/$studentName/*.languageExt 时),要么我有输出路径还列出了每个源文件,例如:

$tempDir/$studentName/studentNameA.java $tempDir/$studentName/studentNameB.java 当我只需要 $tempDir/$studentName/*.java

我认为这应该很容易,我只是想多了。任何改进脚本的提示也很感激。

【问题讨论】:

  • jardir 上的循环没有意义:latestSubmissionDir 是一个单词,而不是单词列表。
  • echo /tempDir/*/*."$languageExt" ?此外,路径可以包含空格、特殊字符等...(引用您的变量)。
  • @user829755 你是对的。我什至没有注意到它,因为它有效。谢谢。

标签: linux bash shell awk


【解决方案1】:

以下是脚本帽子的修订版本:

#/bin/bash

# Extract all jar files into a temp directory called /home/moss/tempJarFiles/studentName
# $1 is the command line argument that contains the path to the institution submission dir.
# $2 is the language extension: c, cpp, java, py

students_dir=$1
languageExt=$2

studentPathsT=( "$students_dir"/*/ )

mossDir='/home/moss'
tempDir='/home/moss/tempJarStorage'

for studentPathT in "${studentPathsT[@]}"; do
  student=$(basename "$studentPathT")
  mkdir "$tempDir/$student"
  submissionDirsT=( "$studentPathT"*/ )
  latestSubmissionDirT=${submissionDirsT[${#submissionDirsT[@]-1]}
  cp "$latestSubmissionDirT"*.jar "$tempDir/$student/"
  unzip -d "$tempDir/$student/" -o -j "$tempDir/$student/*.jar" "*.$languageExt"
  rm "$tempDir/$student"/*.jar
done

# Note that at this point `"$tempDir"/*/*.$languageExt` would expand
# to all extracted submission files, across all students.

# Finally, output each student's extracted files as an unexpanded glob à la
# /{tempDir}/{studentName1}/*.{languageExt}
for pT in "$tempDir"/*/; do
  echo "$pT*.$languageExt"
  # Note: If there is a chance that your filenames contain 
  #       embedded newlines (rare in practice) using `echo` won't work properly
  #       as @Charles Duffy points out.
  #       If that is a concern, use
  #           printf '%s\0' "$pT*.$languageExt"
  #       and process the output with a utility that can process NUL characters
  #       as separators, such as `xargs -0`.
done
  • 它避免使用ls,只使用路径名扩展和数组变量,以便正确处理包含嵌入空格和其他shell元字符的路径。
  • 变量名称中的后缀...T 表示特定路径或路径数组是*T*终止的,即它以/ 结尾。
  • 假设编号子目录不超过9,因为依赖于路径名扩展的隐式词法排序;如果数字更高,则必须应用明确的数字排序。
  • 请注意,传递给 unzip 的 glob(路径名模式)是有意双引号,因为它们应该由 unzip 解释,而不是 shell。
  • 请注意,根据您的原始代码,我假设 $languageExt 不以 . 开头(例如,cpp 而不是 .cpp),尽管您的评论说了什么。

【讨论】:

  • 使用由echo 创建的以换行符分隔的文件名列表并不理想——UNIX 文件名可能包含文字换行符,因此恶意制作的文件名可以发出读取为其他名称的内容进入您的信息流。使用 NUL 作为分隔符要好得多——或 printf '%q\n' "$p",在一行上生成一个 eval 安全的名称。
  • 它绕过了这个问题,直到你使用 echo 的最后一行。但是,在这一点之上,你做的一切都很完美。
  • @CharlesDuffy:对不起,我已经删除了我之前的评论(说使用路径名扩展和数组变量绕过了问题)当你回复时:我意识到${submissionDirsT[@]: -1}确实有问题,它不会保留嵌入的换行符;我已经纠正了这一点。至于你的观点:我在echo 声明之后添加了一个警告;不过,使用printf '%q\n' 会增加额外的引用级别,需要解决,所以我建议改为printf '%s\0'
  • 谢谢。这正是我一直在寻找的,我也学到了一些东西。你对语言分机是正确的。我在事后添加了它以使事情更清楚,但它产生了相反的效果。再次感谢。
  • 更正我自己之前的声明:${someArray[@]: -1} 引用数组的最后一个元素确实正确保留了嵌入的换行符(并且通常比 ${someArray[${#someArray[@]}-1]} 更可取,因为它不需要数组索引是连续的)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-21
  • 1970-01-01
  • 2019-11-15
  • 1970-01-01
  • 1970-01-01
  • 2014-04-06
相关资源
最近更新 更多