Bash查找文件并循环内容。

huangapple go评论62阅读模式
英文:

Bash find files and loop contents

问题

从这个存储库@andrew8088/dotfiles/blob/main/install/bootstrap.sh中借用,我正在尝试使用那里的现有代码来循环我的MacOS $DOTFILES存储库以查找links.prop文件,读取文件内容并运行适当的符号链接。

问题是当我运行bash install/boostrap.sh并使用下面的片段时,我没有得到预期的结果。

install_dotfiles () {
  info 'installing dotfiles'

  local overwrite_all=false backup_all=false skip_all=false

  find -H "$DOTFILES" -maxdepth 2 -name 'links.prop' -not -path '*.git*' | while read linkfile
  do
    echo $linkfile
    cat "$linkfile" | while read line
    do
        echo $line;
        local src dst dir
        src=$(eval echo "$line" | cut -d '=' -f 1)
        dst=$(eval echo "$line" | cut -d '=' -f 2)
        dir=$(dirname $dst)

        mkdir -p "$dir"
        link_file "$src" "$dst"
    done
  done
}

输出

  [ .. ] installing dotfiles
/Users/username/github/dotfiles/zsh/links.prop
/Users/username/github/dotfiles/git/links.prop
  [ OK ] /Users/douglasbeaumont/.env.sh file already exists, skipping

  [ OK ] All installed!

它可以找到文件,但无法读取内容。

zsh/links.prop中有一行$DOTFILES/zsh/rc.zsh=$HOME/.zshrc

英文:

Taking from this repo @andrew8088/dotfiles/blob/main/install/bootstrap.sh I'm trying to use the existing code there to loop my MacOS $DOTFILES repo to find links.prop files, read the contents of the file and run the appropriate symlink.

The problem is when I run the bash install/boostrap.sh with the below snippet I don't get the expected results.

install_dotfiles () {
  info 'installing dotfiles'

  local overwrite_all=false backup_all=false skip_all=false

  find -H "$DOTFILES" -maxdepth 2 -name 'links.prop' -not -path '*.git*' | while read linkfile
  do
    echo $linkfile
    cat "$linkfile" | while read line
    do
        echo $line;
        local src dst dir
        src=$(eval echo "$line" | cut -d '=' -f 1)
        dst=$(eval echo "$line" | cut -d '=' -f 2)
        dir=$(dirname $dst)

        mkdir -p "$dir"
        link_file "$src" "$dst"
    done
  done
}

output

  [ .. ] installing dotfiles
/Users/username/github/dotfiles/zsh/links.prop
/Users/username/github/dotfiles/git/links.prop
  [ OK ] /Users/douglasbeaumont/.env.sh file already exists, skipping

  [ OK ] All installed!

It finds the files fine but won't read the contents.

zsh/links.prop has the line $DOTFILES/zsh/rc.zsh=$HOME/.zshrc.

答案1

得分: 2

考虑这个示例脚本:

#!/bin/bash
printf ''%s' ''test data'' > testfile
while read -r line ; do
  echo "'$line'"
done < testfile

它什么也不输出,但如果你 cat testfile,显然已经写入了内容。这是怎么回事?

问题在于如果 read 在遇到换行符之前遇到文件结束,则会以非零状态退出,这导致 while 循环终止。如果你的文件只有一行,并且没有以换行符结尾,就像上面的 testfile 一样,它看起来好像内容没有被读取,但实际上不是这种情况。

如果不能保证每行都以换行符结尾,那么有一个解决方法:

#!/bin/bash
printf ''%s' ''test data'' > testfile
while read -r line || [[ -n "'$line'" ]] ; do
  echo "'$line'"
done < testfile

未终止的行仍会导致 read 以非零状态退出,但因为 line 仍然有内容,你可以在退出循环之前检查是否有内容,并在处理后退出循环。

英文:

Consider this sample script:

#!/bin/bash
printf '%s' 'test data' > testfile
while read -r line ; do
  echo "$line"
done < testfile

It prints nothing, but if you cat testfile it's clearly populated. What gives?

The problem here is that read exits with a non-zero status if it encounters end-of-file before a newline, which causes the while loop to terminate. If your file only has a single line and it's not newline-terminated, like testfile above, then it will look like the contents aren't being read but that's not actually the case.

If you can't guarantee every line is newline-terminated, then there is a workaround:

#!/bin/bash
printf '%s' 'test data' > testfile
while read -r line || [[ -n "$line" ]] ; do
  echo "$line"
done < testfile

The unterminated line will still cause read to exit non-zero, but because line is still populated you can follow that up with a check that there's something in it and process it before exiting the loop.

huangapple
  • 本文由 发表于 2023年5月18日 02:36:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76275239.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定