how to repack an epub file from command line

September 9, 2018 - Reading time: 5 minutes
To unzip the epub, move the ePub to a folder, cd to it then simply:
unzip MyEbook.epub
To zip up an epub:
1. zip -X MyNewEbook.epub mimetype
2. zip -rg MyNewEbook.epub META-INF -x \*.DS_Store
3. zip -rg MyNewEbook.epub OEBPS -x \*.DS_Store
Some explanations necessary here. We start each line with two flags:
-r (recursive)
This means move down through any directories/folders recursively, ensuring that everything in the folders specified gets included
-g (grow file)

even more concise :
// To unzip the epub, move the ePub to a folder, cd to it then simply:
zip -rX ../my.epub mimetype META-INF/ OEBPS/

Without -X you could get the following when validating it with EpubCheck:

ERROR: my.epub: Mimetype entry must not have an extra field in its ZIP header

If mimetype is not the first in the epub file EpubCheck prints the following:

ERROR: my.epub: Mimetype entry missing or not the first in archive

Linux uses the name of the current folder as the epub filename:
zip -rX "../$(basename "$(realpath .)").epub" mimetype $(ls|xargs echo|sed 's/mimetype//g')

I found this version also worked better for epubs I found that don't use the OEBPS folder. I don't know if not having that folder is valid per standards, but I found examples of it being missing in the wild.



how to mount qcow2 image

August 14, 2018 - Reading time: ~1 minute

Step 1 - Enable NBD on the host

modprobe nbd max_part=8

Step 2 - Connect the QCOW2 as a network block device

qemu-nbd --connect=/dev/nbd0 /var/lib/vz/images/100/vm-100-disk-1.qcow2

Step 3 - List partitions inside the QCOW2

fdisk /dev/nbd0 -l

Step 4 - Mount the partition from the VM

mount /dev/nbd0p1 /mnt/somepoint/

You can also mount the filesystem with normal user permissions, ie. non-root:

mount /dev/nbd0p1 /mnt/somepoint -o uid=$UID,gid=$(id -g)

Step 5 - After you're done, unmount and disconnect

umount /mnt/somepoint/
qemu-nbd --disconnect /dev/nbd0
rmmod nbd

reload .bashrc settings without logging out and back in

August 10, 2018 - Reading time: 4 minutes

You can enter the long form command:

source ~/.bashrc

or you can use the shorter version of the command:

. ~/.bashrc

or you could use:
exec bash

To complement and contrast the above commands with . ~/.bashrc and exec bash:

Both solutions effectively reload ~/.bashrc, but there are differences:

  • . ~/.bashrc or source ~/.bashrc will preserve your current shell session:

    • Except for the modifications that reloading ~/.bashrc into the current shell (sourcing) makes, the current shell process and its state are preserved, which includes environment variables, shell variables, shell options, shell functions, and command history.
  • exec bash, or, more robustly, exec "$BASH"[1], will replace your current shell with a new instance, and therefore only preserve your current shell's environment variables (including ones you've defined ad hoc, in-session).

    • In other words: Any ad-hoc changes to the current shell in terms of shell variables, shell functions, shell options, command history are lost.

Depending on your needs, one or the other approach may be preferred.


[1] exec bash could in theory execute a different bash executable than the one that started the current shell, if it happens to exist in a directory listed earlier in the $PATH. Since special variable $BASH always contains the full path of the executable that started the current shell, exec "$BASH" is guaranteed to use the same executable.
A note re "..." around $BASH: double-quoting ensures that the variable value is used as-is, without interpretation by Bash; if the value has no embedded spaces or other shell metacharacters (which is not likely in this case), you don't strictly need double quotes, but using them is a good habit to form.


generate a list of a site's URLs using wget

June 12, 2018 - Reading time: ~1 minute

You can use wget to generate a list of the URLs on a website.

Spider example.com, writing URLs to urls.txt, filtering out common media files (css, js, etc..):

wget --spider -r http://www.example.com 2>&1 | grep '^--' | awk '{ print $3 }' | grep -v '\.\(css\|js\|png\|gif\|jpg\|JPG\)$' > urls.txt

Note that this gives a list that duplicates URLs.

If you mirror instead of spider you seem to get a more comprehensive list without duplicates:

wget -m http://www.example.com 2>&1 | grep '^--' | awk '{ print $3 }' | grep -v '\.\(css\|js\|png\|gif\|jpg\|JPG\)$' > urls.txt

This will download all pages of the site into a directory with the same name as the domain.


switch monitors from the command line

February 20, 2018 - Reading time: ~1 minute

With the commands

xrandr --output VGA-0 --auto
xrandr --output LVDS --off 

The screen automatically transfers to the external display. It doesn't even need sudo powers. To find out the name of the displays just do:

xrandr -q

Which should give something like:

VGA-0 connected 1280x1024+0+0 (normal left inverted right x axis y axis) 338mm x 270mm
...
LVDS connected (normal left inverted right x axis y axis)
...

Extending the displays can probably be achieved in a similar manner.


mount a disk image from the command line

January 27, 2016 - Reading time: 2 minutes

If it was a hard-drive image with a MBR partition table, I would fdisk the image to find the offset for the partition I need to mount.

fdisk -lu /path/disk.img

Then I would mount it passing the offset.

mount -o loop,offset=xxxx /path/disk.img /mnt/disk.img.partition

The offset value is in bytes, whereas fdisk shows a block count, so you should multiply the value from the "Begin" or "Start" column of the fdisk output by 512 (or whatever the block size is) to obtain the offset to mount at.

On most modern GNU system the mount command can handle that:

mount -o loop file.iso /mnt/dir

to unmount you can just use the umount command

umount /mnt/dir

If your OS doesn't have this option you can create a loop device:

losetup -f # this will print the first available loop device ex:/dev/loop0
losetup /dev/loop0 /path/file.iso #associate loop0 with the specified file
mount /dev/loop0 /mnt/dir #It may be necessary specify the type (-t iso9660)

to umount you can use -d:

umount /mnt/dir
losetup -d /dev/loop0

If the file have partitions, example a HD image, you can use the -P parameter (depending on you OS), it will map the partitions in the file content:

losetup -P /dev/loop0 /path/file.iso # will create /dev/loop0 
ls /dev/loop0p* #the partitions in the format /dev/loop0pX