【问题标题】:how to determine a newline in bash?如何确定bash中的换行符?
【发布时间】:2019-10-30 03:39:16
【问题描述】:

一个文件:

a
b

运行命令

dd if=file count=1 skip=0 bs=1 # show a
dd if=file count=1 skip=1 bs=1 # show "newline"
dd if=file count=1 skip=2 bs=1 # show b

我想在给定偏移量之前搜索第一个“换行符”的偏移量,在 bash 脚本中使用“if”语句(这是一种虚拟方式):

para1=$1
while(1)
do
    c=$(dd if=file count=1 bs=1 skip=$para1)
    if [ $c -eq "\n" ]   # How to write this line?
    then
        break
    fi
    para1=`expo $para - 1`
done
echo $para1
bash fun.sh 2
# the output should be 1

其实我在这里找到了解决办法:How do i compare if my variable holds a newline character in shell Script

if [ ${#str} -eq 0 ] 

但我想知道它是否足够强大,还是有更优雅的方法来做到这一点?

【问题讨论】:

  • 我不明白你的任务:什么是“换行偏移”,什么是“给定偏移”,“反向”是什么意思?请注意,$ 仅用于说明换行符。它实际上并不存在。
  • 例如:一个文件为“1234567”,“1”的偏移量为0,“3”的偏移量为2,给定偏移量2,我需要反向搜索“7”,所以没有,但是如果我需要反向搜索“1”,找到的偏移量是0。“$”确实带了一个字符。使用“dd skip=xxx count=1 bs=1”你可以找到行的最后一个字符和下一行的第一个字符之间的间隙@BenjaminW。
  • awk 这样的东西会做吗?前任。 awk -v ndx=3 'sum+length($0) < ndx {sum+=length($0); next} {print sum; exit}' file 其中ndx 的值是您要查找的文件中的字符,而索引之前的换行符的字符数是结果? (在这种情况下为1)。或者给定包含"hello\nworld\nthis\nis\na\ntest\n"ndx=12的文件("this"中的'h'),结果是10't'之前的换行符)
  • $ 表示换行的唯一地方是正则表达式。我不明白这与这项任务有什么关系。
  • $( ) 总是在其读取内容的末尾修剪任何换行符,因此结果将从不匹配\n\r\n。解决此问题的一种方法是在末尾添加保护性非换行符,然后将其删除:c=$(dd if=file count=1 bs=1 skip=$para1; echo x); c=${c%x}。此外,对于测试,-eq 进行数字比较,而不是字符串比较。此外,与"\n" 相比,将与后跟字母“n”的文字反斜杠进行比较,不是换行符。对于换行符,请使用 $'\n'

标签: bash sh newline


【解决方案1】:

请关注代码:

c=$(dd if=test1 skip=2 bs=1 count=1)

man bash 的命令替换部分描述:

Bash 通过执行命令 ... 来执行扩展,并删除任何尾随换行符。

因此,上面dd 命令结果中的换行符被删除。 您将通过下面的测试代码看到它:

for (( i=1; i<=3; i++ )); do
    c="$(dd if=test1 skip="$i" bs=1 count=1 2>/dev/null)"
    echo "skip = $i"
    echo -n "$c" | xxd
done

一般bash不适合显式处理换行符 特点 因为 bash 有时会自动删除或添加它。

如果perl 是您的选择,请尝试以下操作:

perl -0777 -ne '
    $given = 3;     # an example of the given offset
    printf "character at offset %d = %s\n", $given, substr($_, $given, 1);
    $pos = rindex(substr($_, 0, $given), "\n", $given);
    if ($pos < 0) {
        print "not found\n";
    } else {
        printf "newline found at offset %d\n", $given - $pos - 1;
    }
' file

如果你更喜欢bash,这里是 bash 中的替代方案:

file="./file"
given=3                               # an example of the given offset

str="$(xxd -ps "$file" | tr -d '\n')" # to the hexadecimal expression
for (( i=given; i>=0; i-- )); do
    j=$(( i * 2 ))
    c="${str:$j:2}"                   # substring offset j, length 2
    if [[ $c = "0a" ]]; then          # search for the substring "0a"
        printf "newline found at offset %d\n" $(( given - i - 1 ))
        exit
    fi
done
echo "not found"

概念与 perl 版本相同。它首先将整个文件转换为十六进制表达式,并从给定位置开始向后搜索子字符串“0a”。

希望这会有所帮助。

【讨论】:

  • 我刚刚用 bash 替代品更新了我的答案。请尽情享受!
猜你喜欢
  • 2016-12-02
  • 2014-02-15
  • 2011-01-27
  • 2019-12-17
  • 2012-09-26
  • 2013-10-21
  • 1970-01-01
  • 1970-01-01
  • 2011-11-05
相关资源
最近更新 更多