Please focus on the code:
c=$(dd if=test1 skip=2 bs=1 count=1)
The Command Substitution section of man bash
describes:
Bash performs the expansion by executing command ... with any trailing newlines deleted.
Because of this the newline in the result of dd
command above is removed.
You'll see it by the test code below:
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
In general bash
is not suitable for explicitly dealing with the newline
character
because bash sometimes automatically removes or adds it.
If perl
is your option, please try the following:
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
If you prefer bash
, here is the alternative in 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"
The concept is same as the perl version. It first converts the whole file into the hexadecimal expression and searches for the substring "0a" starting at the given position backwards.
Hope this helps.
$
is only to illustrate a linebreak. It's not really there.awk
do? Ex.awk -v ndx=3 'sum+length($0) < ndx {sum+=length($0); next} {print sum; exit}' file
where the value ofndx
is the character in the file you are looking for and the character number of the newline prior to the index is the result? (1
in this case). Or given the file containing"hello\nworld\nthis\nis\na\ntest\n"
andndx=12
(the'h'
in"this"
), the result is10
(the newline before't'
)$
means newline is in regular expressions. I don't see how that's relevant to this task.$( )
always trims any newlines at the end of what it reads, so the result will never match\n
or\r\n
. One way around this is to add a protective non-newline at the end, then remove it:c=$(dd if=file count=1 bs=1 skip=$para1; echo x); c=${c%x}
. Also, for the test,-eq
does numeric comparisons, not string comparison. Also, comparing to"\n"
will compare to a literal backslash followed by the letter "n", not a newline. For a newline, use$'\n'
.