how to reassign page number in DJVU file? - linux

Is there a simple way to renumber pages in a DJVU file?
Example:
I've got a book, and page 1 is actually the cover, and so on, such that the actual page 1 of the book is at, say, 10 in the document; what I'd like to do is call them something like C,i,ii,..., and then 1,2,...
I know it can be done, since I've got other books in this format with this numbering, and I'd like to do it on Linux, better if via terminal.
Thanks,
N

to renumber
for (( i=11; i<=823; i++ ))
do
djvused new.djvu -e "select $i; set-page-title $((i-10)); save"
done
to rename
djvused new.djvu -e 'select 2; set-page-title ii; save'

It's slightly offtopic. Just in case someone needs to do the same thing on Windows using PowerShell:
for($i=11; $i -le 823; $i++){
$j=($i-10)
$args = "new.djvu -e ""select $i; set-page-title $j; save"""
write-host "djvused $args"
start-process djvused $args -NoNewWindow -wait
}

Related

Create a file named with a specific pattern

Need some help here. I need to create an executable file for every user that exists on the system ( Linux ) and the format for file is the following :
fis_nr_username
where nr stands for 1st file, 2nd file etc...
EXAMPLE OF SITUATION
Users on machine :
stud01
stud02
stud03
I need a file for each of them to be executable and look like this :
file_1_stud01
file_2_stud02
file_3_stud03
You could loop through the user list, then loop through file number (here 0 to 10). Use printf with %03d to pad with zeros.
#!/usr/bin/env bash
username="stud01 stud02 stud03"
for name in $username; do
for ((i=0; i<11; i++)); do
printf "file_%03d_%s\n" $i $name
done
done
You could make this a function and put it in .bashrc
newfiles() {
username="$#"
for name in $username; do
for ((i=0; i<3; i++)); do
printf "file_%03d_%s\n" $i $name
done
done
}
call the function from terminal with: newfiles firstuser serconduser. Output:
fis_000_firstuser
fis_001_firstuser
fis_002_firstuser
fis_000_seconduser
fis_001_seconduser
fis_002_seconduser

0999: Value too great for base (error token is "0999")

This is a shortened-version of a script for reading 8mm tapes from a EXB-8500 with an autoloader (only 10 tapes at a time maximum) attached. It dd's in tape data (straight binary) and saves it to files that are named after the tape's 4-digit number (exmaple D1002.dat) in both our main storage and our backup. During this time it's logging info and displaying its status in the terminal so we can see how far along it is.
#!/bin/bash
echo "Please enter number of tapes: [int]"
read i
j=1
until [ $i -lt $j ]
do
echo "What is the number of tape $j ?"
read Tape_$j
(( j += 1 ))
done
echo "Load tapes into the tower and press return when the drive is ready"
read a
j=1
until [ $i -lt $j ]
do
k="Tape_$j"
echo "tower1 $j D$(($k)) `date` Begin"
BEG=$j" "D$(($k))" "`date`" ""Begin"
echo "tower1 $j D$(($k)) `date` End"
END=$j" "D$(($k))" "`date`" ""End"
echo "$BEG $END"
echo "$BEG $END"
sleep 2
(( j += 1 ))
done
echo "tower1 done"
Everything was hunky-dory until we got under 1000 (startig at 0999). Error code was ./tower1: 0999: Value too great for base (error token is "0999"). Now I already realize that this is because the script is forcing octal values when I type in the leading 0, and I know I should insert a 10# somewhere in the script, but the question is: Where?
Also is there a way for me to just define Tape_$j as a string? I feel like that would clear up a lot of these problems
To get the error, run the script, define however many tapes you want (at least one, lol), and insert a leading 0 into the name of the tape
EXAMPLE:
./test
Please enter number of tapes: [int]
1
What is the number of tape 1?
0999
./test: 0999: Value too great for base (error token is "0999")
You don't want to use $k as a number, but as a string. You used the numeric expression to evaluate a variable value as a variable name. That's very bad practice.
Fortunately, you can use variable indirection in bash to achieve your goal. No numbers involved, no error thrown.
echo "tower1 $j ${!k} `date` Begin"
BEG=$j" "D${!k}" "`date`" ""Begin"
And similarly in other places.

Shell Script that performs different functions based on input from file

I am trying to merge two very different scripts together for consolidation and ease of use purposes. I have an idea of how I want these scripts to look and operate, but I could use some help getting started. Here is the flow and look of the script:
The input file would be a standard text file with this syntax:
#Vegetables
Broccoli|Green|14
Carrot|Orange|9
Tomato|Red|7
#Fruits
Apple|Red|15
Banana|Yellow|5
Grape|Purple|10
The script would take the input of this file. It would ignore the commented portions, but use them to dictate the output. So based on the fact that it is a Vegetable, it would perform a specific function with the values listed between the delimiter (|). Then it would go to the Fruits and do something different with the values, based on that delimiter. Perhaps, I would add Vegetable/Fruit to one of the values and dependent on that value it would perform the function while in this loop to read the file. Thank you for your help in getting this started.
UPDATE:
So I am trying to implement the IFS setup and thought of a more logical arrangement. The input file will have the "categories" displayed within the parameters. So the setup will be like this:
Vegetable|Carrot|Yellow
Fruit|Apple|Red
Vegetable|Tomato|Red
From there, the script will read in the lines and perform the function. So basically this type of setup in shell:
while read -r category item color
do
if [[ $category == "Vegetable" ]] ; then
echo "The $item is $color"
elif [[ $category == "Fruit" ]] ; then
echo "The $item is $color"
else
echo "Bad input"
done < "$input_file"
Something along those lines...I am just having trouble putting it all together.
Use read to input the lines. Do a case statement on their prefix:
{
while read DATA; do
case "$DATA" in
\#*) ... switch function ...;;
*) eval "$FUNCTION";;
esac
done
} <inputfile
Dependent on your problem you might want to experiment with setting $IFS before reading and read multiple variables in 1 go.
You can redefine the processing function each time you meet a # directive:
#! /bin/bash
while read line ; do
if [[ $line == '#Vegetables' ]] ; then
process () {
echo Vegetables: "$#"
}
elif [[ $line == '#Fruits' ]] ; then
process () {
echo Fruits: "$#"
}
else
process $line
fi
done < "$1"
Note that the script does not skip empty lines.

Read numbers from file until line < n

As shocked as I am, I can't find this anywhere, and my bash skills are still sub-par.
I have a text file of prime numbers:
2\n
3\n
5\n
7\n
11\n
etc...
I want to pull all primes under 2^32 (4294967296) plus one additional prime number, and save these primes to the own text file formatted the same way. Also, my file has just over 1.3 billion lines so far, so stopping after the limit would be ideal.
Update: Problem.
The bash script has been looping through these 11 numbers for quite some time without me noticing:
4232004449
4232004479
4232004493
4232004509
4232004527
4232004533
4232004559
4232004589
4232004593
4232004613
004437
What's even weirder is I grepped primes.txt (the original) and "^004437" was nowhere to be found. Is this some kind of limitation of bash?
Update: Solution
It appears to be some kind of limitation of something, I really don't know what. I'm re-chosing the perl script as my answer because not only did it work, but it created the ~2GB from nothing in ~80 seconds and included the additional prime. Go here for a solution to the bash error.
$ perl -lne 'print; last if $_ > 2**32' < myprimes.txt > myprimes2.txt
Gives you the input series of primes up to one prime past 2**32, then stops. Does not read source file into memory.
In shell, without loading the whole 1.3 billion numbers into memory, you can use:
n=4294967296
last=0
while read number
do
if [ $last -gt $n ]
then break
fi
echo $number
last=$number
done < primes.txt > primes2.txt
You could lose the last variable too:
n=4294967296
while read number
do
echo $number
if [ $number -gt $n ]
then break
fi
done < primes.txt > primes2.txt
This is very easy to do in Bash! Just cat the file primes.txt to read it, go through each number, check that the number is less than 2^32, and if it is, append it to primes2.txt.
The exact code is below.
#!/bin/bash
n=4294967296; # 2^32
for i in `cat primes.txt`
do
if [ $i -le $n ]
then
echo $i >> primes2.txt;
fi
done
Or you can use this simple Python solution, which does not require loading the entire file into memory.
new_primes = open('primes2.txt', 'a')
n = 2**32
[new_primes.write(p) for p in open('primes.txt', 'r') if int(p) < n]
I would recommend doing something like this in Perl:
EDIT: Hm, it was probably the array that used up all your RAM - this should be more friendly to your resources.
#!/usr/bin/env perl
use warnings;
use strict;
my $max_value = ( 2 ** 32);
my $input_file = 'primes.txt';
my $output_file = 'primes2.txt';
open( my $INPUT_FH, '<', $input_file )
or die "could not open file: $!";
open ( my $OUTPUT_FH, '>', $output_file )
or die "could not open file: $!";
foreach my $prime ( <$INPUT_FH> ) {
chomp($prime);
unless ( $prime >= $max_value ) { print $OUTPUT_FH "$prime","\n"; }
}

Improve my password generation script

I have created a little password generation script. I'm curious to what improvements can be made for it except input error handling, usage information etc. It's the core functionality I'm interested in seeing improvements upon.
This is what it does (and what I like it to do):
Keep it easy to change which Lowercase characters (L), Uppercase characters (U), Numbers (N) and Symbols (S) that are used in passwords.
I'd like it to find a new password of legnth 10 for me in max two seconds.
It should take a variable length of the password string as an argument.
Only a password containing at least one L, U, N and S should be accepted.
Here is the code:
#!/bin/bash
PASSWORDLENGTH=$1
RNDSOURCE=/dev/urandom
L="acdefghjkmnpqrtuvwxy"
U="ABDEFGHJLQRTY"
N="012345679"
S="\-/\\)?=+.%#"
until [ $(echo $password | grep [$L] | grep [$U] | grep [$N] | grep -c [$S] ) == 1 ]; do
password=$(cat $RNDSOURCE | tr -cd "$L$U$N$S" | head -c $PASSWORDLENGTH)
echo In progress: $password # It's simply for debug purposes, ignore it
done
echo Final password: $password
My questions are:
Is there a nicer way of checking if the password is acceptable than the way I'm doing it?
What about the actual password generation?
Any coding style improvements? (The short variable names are temporary. Though I'm using uppercase names for "constants" [I know there formally are none] and lowercase for variables. Do you like it?)
Let's vote on the most improved version. :-)
For me it was just an exercise mostly for fun and as a learning experience, albeit I will start using it instead of the generation from KeepassX which I'm using now. It will be interesting to see which improvements and suggestions will come from more experienced Bashistas (I made that word up).
I created a little basic script to measure performance: (In case someone thinks it's fun)
#!/bin/bash
SAMPLES=100
SCALE=3
echo -e "PL\tMax\tMin\tAvg"
for p in $(seq 4 50); do
bcstr=""; max=-98765; min=98765
for s in $(seq 1 $SAMPLES); do
gt=$(\time -f %e ./genpassw.sh $p 2>&1 1>/dev/null)
bcstr="$gt + $bcstr"
max=$(echo "if($max < $gt ) $gt else $max" | bc)
min=$(echo "if($min > $gt ) $gt else $min" | bc)
done
bcstr="scale=$SCALE;($bcstr 0)/$SAMPLES"
avg=$(echo $bcstr | bc)
echo -e "$p\t$max\t$min\t$avg"
done
You're throwing away a bunch of randomness in your input stream. Keep those bytes around and translate them into your character set. Replace the password=... statement in your loop with the following:
ALL="$L$U$N$S"
password=$(tr "\000-\377" "$ALL$ALL$ALL$ALL$ALL" < $RNDSOURCE | head -c $PASSWORDLENGTH)
The repetition of $ALL is to ensure that there are >=255 characters in the "map to" set.
I also removed the gratuitous use of cat.
(Edited to clarify that what appears above is not intended to replace the full script, just the inner loop.)
Edit: Here's a much faster strategy that doesn't call out to external programs:
#!/bin/bash
PASSWORDLENGTH=$1
RNDSOURCE=/dev/urandom
L="acdefghjkmnpqrtuvwxy"
U="ABDEFGHJLQRTY"
N="012345679"
# (Use this with tr.)
#S='\-/\\)?=+.%#'
# (Use this for bash.)
S='-/\)?=+.%#'
ALL="$L$U$N$S"
# This function echoes a random index into it's argument.
function rndindex() { echo $(($RANDOM % ${#1})); }
# Make sure the password contains at least one of each class.
password="${L:$(rndindex $L):1}${U:$(rndindex $U):1}${N:$(rndindex $N):1}${S:$(rndindex $S):1}"
# Add random other characters to the password until it is the desired length.
while [[ ${#password} -lt $PASSWORDLENGTH ]]
do
password=$password${ALL:$(rndindex $ALL):1}
done
# Now shuffle it.
chars=$password
password=""
while [[ ${#password} -lt $PASSWORDLENGTH ]]
do
n=$(rndindex $chars)
ch=${chars:$n:1}
password="$password$ch"
if [[ $n == $(( ${#chars} - 1 )) ]]; then
chars="${chars:0:$n}"
elif [[ $n == 0 ]]; then
chars="${chars:1}"
else
chars="${chars:0:$n}${chars:$((n+1))}"
fi
done
echo $password
Timing tests show this runs 5-20x faster than the original script, and the time is more predictable from one run to the next.
you could just use uuidgen or pwgen to generate your random passwords, maybe later shuffling some letters around or something of the sort
secpwgen is very good (it can also generate easier to remember diceware passwords) - but has almost disappeared from the net. I managed to track down a copy of the 1.3 source & put it on github.
It is also now part of Alpine Linux.

Resources