用于递归地将文件路径添加到文件前面的脚本

用于递归地将文件路径添加到文件前面的脚本

我是一名评分员,提交给我的文件最终存放在一个以学生姓名命名的文件夹中,该文件夹本身位于我的 Linux 共享上的特定文件夹中。

目前,我浏览每个源文件并在每个文件的顶部手动添加注释,以便当我打印它们时我可以知道哪些文件属于哪些学生。

我想要做的是递归地浏览作业文件夹,当我下拉到每个学生文件夹时,使用学生目录名称在该文件夹中每个文件的顶部添加一条注释,以了解要在注释中添加哪些内容。

就在文件顶部添加注释而言似乎很相似,但我不确定当我放入每个学生文件夹时如何动态创建注释。

最近更新

仍然无法正常工作,但这是我所做的更改,因此您不必寻找它们。

我做了一些改变:

  • printf 语句中的单引号现在是双引号,因为'inisn't提前终止了它。
  • 更改-writable-perm 664可写会引发错误,并且我尝试更改的所有文件在上传时都设置为 644。如果您知道比这更好的方法,请告诉我。
  • 如果我正确理解 exec 现在 $1 未声明(添加echo $1exec 参数证实了这一点),所以我在 exec 参数末尾添加_filepath={}并删除了。{}
  • 初始化_dirname_filepath
  • 在使用正则表达式隔离目录名称的两行中,双引号未关闭。现在 _dirname 成功地只保存了目录的名称
  • 现在调用 ed_filepath

我很确定它不起作用的原因是因为调用 ed 的行中的单引号关闭了 exec 参数。

当前代码:

student_head_action() {
   # We can't use parameter expansion on $PWD because of recursion
   local _dirname="${1%/*}"
   _dirname="${_dirname##*/}"

   [[ -d $1 ]] && return 0
   if ! [[ -w $1 && -f $1 ]]; then
      printf '%s\n' "$1 does not exist or is not writeable, skipping"
      return 1
   fi
   ed -s "$1" <<< $'0a\n'"//${_dirname}"$'\n.\n,s/\r//g\nw'
}

student_head() {
   local _file
   if (( $# )); then
      for _file; do
         student_head_action "${_file}" || _retval=1
      done
   else
      if shopt -qs globstar; then
         for _file in **/*; do
            student_head_action "${_file}" || _retval=1
         done
         shopt -u globstar
      else
         printf "%s\n" "Globstar isn't available, attempting to use GNU find ..."
         find . -type f -perm 644 -exec bash -c '
            _filepath={}
            _dirname=$_filepath
            _dirname="${_dirname%/*}"
            _dirname="${_dirname##*/}"
            echo $_dirname
            ed -s "$_filepath" <<< '"$'0a\n'"'"//${_dirname}"'"$'\n.\n,s/\r//g\nw'" \;
      fi
   fi
   return "${_retvalue-0}"

答案1

您可以student_head在文件夹中运行,以自动将文件夹名称作为标题添加到其中及其子目录中的可写文件中:

student_head_action() {
    # We can't use parameter expansion on $PWD because of recursion
    local _dirname="${1%/*}"
    _dirname="${_dirname##*/}"

    [[ -d $1 ]] && return 0
    if ! [[ -w $1 && -f $1 ]]; then
        printf '%s\n' "$1 does not exist or is not writeable, skipping"
        return 1
    fi
    bash -c "ed -s {} <<< $'0a\n'"# Student: ${_dirname}"$'\n.\n,s/\r//g\nw'"
}

student_head() {

    local _file
    if (( $# )); then
        for _file; do
            student_head_action "${_file}" || _retval=1
        done
    else
        if shopt -s globstar > /dev/null 2>&1; then
            for _file in **/*; do
                student_head_action "${_file}" || _retval=1
            done
           shopt -u globstar
        else
            printf '%s\n' 'Globstar isn't available, attempting to use GNU find...'
            find . -type f -writable -exec bash -c '
                _dirname="${1%/*}\
                _dirname="${_dirname##*/}\
                ed -s "$1" <<< '"$'0a\n'"'"# Student: ${_dirname}"'"$'\n.\n,s/\r//g\nw'" {} \;
        fi                
    fi

    return "${_retval-0}"
}

如果~/.bashrc您希望student_head用户在使用bash.

student_head可以通过两种方式调用:

  1. 毫无争议。在此模式下,当前目录及其子目录中的所有可写文件都预先添加了标头。
  2. 以文件名作为参数。在此模式下,只有参数中列出的文件才会预先添加标头。

如果参数中的文件不存在,student_head则返回退出状态 1。

应该提到的是,该脚本使用globstar,这需要bash>=4.0.

答案2

find这是结合和 的解决方案ed

add_header() {
   declare regex IFS='|'
   (( $# )) && regex="^($*)$" || regex=""
   find "$PWD" -type f -exec bash -c ' 
      ( exec grep -E -qs -e "$0" <<<"${1##*/}" ) || exit
      _dirname="${1%/*}"
      _dirname="${_dirname##*/}"
      exec ed -s "${1}" <<EOF
0a
# Student: ${_dirname}
.
wq
EOF
   ' "${regex:-.+}" '{}' \;
   return 0
}

add_header                    # all files in current directory recursively
add_header file1 file2 file3  # only named files in current directory recursively

相关内容