简体   繁体   中英

how to determine a newline in bash?

A file:

a
b

run command

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

I want to search the offset of the first "newline" before a given offset, with 'if' statement in a bash script (which is a dummy way):

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

Actually I have found a solution here: How do i compare if my variable holds a newline character in shell Script

if [ ${#str} -eq 0 ] 

But I wonder is it robust enough, or is there more elegant way to do it?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM