一份文件:
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'语句在给定偏移量之前搜索第一个"newline"的偏移量(这是一种伪方法):
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
实际上,我在这里找到了解决方案:如何比较我的变量在Shell脚本中是否包含换行符
if [ ${#str} -eq 0 ]
但是我想知道它是否足够健壮,还是有更优雅的方法呢?
分析解答
请专注于代码:
c=$(dd if=test1 skip=2 bs=1 count=1)
man bash
的“命令替换”部分描述了:
Bash performs the expansion by executing command ... with any trailing newlines deleted.
因此,删除了上面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"。
希望这可以帮助。