All the balls are the same colour!
Credit: Derren Brown linked to Daniell Owengrub's blog which linked to SyFy which linked to David Novick (creator of image)
I spent ages trying to get Orca to read selected text but there are a mind boggling number of options and while the GNOME (Ubuntu's default desktop manager) documentation is pretty good it never really worked. On further reading there seems to be some issue with Firefox and it was unclear if this had been resolved. I could get the Accessibility Options box to pop up using the short cut keys but none of the key bindings seemed to work for me. It's a shame because Orca comes with all sorts of goodies like reading mnemonics as text, reading camel case words as separate words (very handy if you read a lot of technical documentation!). Anyway, I couldn't get it to work so found another solution; not quite as feature rich but it does exactly what i want.
You need 2 pieces of software installed: something to read selected text (xsel
) and something to read it out (espeak
`) so install both of those:
sudo apt install espeak xsel
To test xsel
is working:
- Open a terminal window.
- Use your mouse to highlight some text in the window.
- Type:
xsel
. Your selected text should be returned by the command.
To test espeak
is working just type:
echo "MrN is Ace" | espeak
and it should read out what is true ;)
This paragraph is from the future! On Ubuntu 22.04, I didn't hear any noise coming from epeak
running in the terminal window on my Ubuntu desktop. This is because you have to specify which audio output device is associated with which application. The easiest way to do this, is to play something long (e.g. cat /etc/services | espeak
) and while it is playing, load in the *Volume Control" application. In the Playback tab (first tab) you will see the Terminal application and its sound meter. Select the audio output device for Terminal and you are good to go. Now back to the past...
Now we just need to put that together. Under GNOME (other Desktop managers may do it differently) we'll create a shortcut key binding to run our command on a magic key combo.
Ubuntu 20
- Open Settings application.
- Go to Devices.
- Go to Keyboard.
- Go down to the bottom and click +.
Ubunti 22
1.Open Settings application.
- Go to Keyboard.
- Go to Keyboard shortcuts
- Click View and Customise Shortcuts.
- Scroll down to Custom Shortcuts and click it.
- Go down to the bottom and click +.
Then:
- Enter a name as "Read selected text".
- Enter command as:
bash -c "xsel | sed -e :a -e '$!N;s/\n/ /;ta'| espeak"
- Click shortcut then make the key combination. I use
CMD+[
on my Mac soWin+[
seemed simple on my PC. - On my Mac the read-text command is a toggle as it's built in. This is not the case when just running a command. I should probably put the read text command into a script so it can detect if it's already running, restart it etc, but that can be a job for another day. For the moment I just need to get up and running, so we'll create something that kills
espeak
. So create another entry by hitting the + button. - Enter a name as "Stop read selected text".
- Enter command as:
bash -c "kill `ps -au | grep '[0-9] espeak$' | awk '{print $2}'`"
- In this case I just picked the bracket next to it as it has the least impact on muscle memory.
That's it, it works in the text editor, browsers and everywhere else. Some browsers use CSS to stop you selecting the text but if you press F7
it'll switch on caret mode which lets you highlight text again. In applications (not web browsers) this is off my default but you should be able to toggle it with F7
too.
This is a tutorial and example of how Bash increases productivity.
We know that a Java archive is just a zip archive so it contains lots of files. We want to create our own index of what they contain so we are going to unpack them and create an index of their contents. Here is the situation.
$ ls -l
total 48616
-rwxr-xr-x 1 davidnewcomb staff 12952991 28 Nov 13:57 MRN.ear
-rwxr-xr-x 1 davidnewcomb staff 11642532 15 Sep 2017 MRN.war
-rwxr-xr-x 1 davidnewcomb staff 289943 21 May 2018 client.jar
Let's practice with one to start with. The Java comes with a jar
program to help you play with the file format. First we need a folder name:
file="MRN.ear"
dir=`echo $file | sed 's/\./_/'`
This writes a line with MRN.ear into the pipe, sed
takes each line and looks for a period followed by everything and replaces it with nothing. The result is assigned to a variable called dir
.
Next we are going to do the work using our new variable. First make a directory:
mkdir $dir
Then go into it:
mkdir $dir ; cd $dir
Next unpack the archive, we have to remember that we are actually a directory below the location of the archive so we need to prefix ../
to the path.
mkdir $dir ; cd $dir ; tar -xf ../$file
Finally we need to make the archive catalogue. So back up a directory level find
what we want:
mkdir $dir ; cd $dir ; tar -xf ../$file ; cd .. ; find $dir > $dir.find.txt
That'll work with one of them, but we have hundreds! No problem, we can just wrap it all in a loop.
for file in `ls`; do dir=`echo $file | sed 's/\./_/'` ; mkdir $dir ; cd $dir ; tar -xf ../$file ; cd .. ; find $dir > $dir.find.txt ; done
for
runs once for each item in a white space (or line break) separated list. We are running ls
to generate the list. Each item in the list will be assigned to $file
and then we just follow our normal path from before.
We have some choices now depending on what kind of resources you have. Bash has the amazing ability to run tasks in the background so waiting for a long command to complete just means you can do something else for a bit! You can push a task into the background by adding an ampersand to the end. For one command it's
echo "hello" &
or we can chain them together like so:
(cat /etc/hosts | grep 127) &
(cd bin ; ls) &
Let's add that to our command:
for file in `ls`; do (dir=`echo $file | sed 's/\./_/'` ; mkdir $dir ; cd $dir ; tar -xf ../$file ; cd .. ; find $dir > $dir.find.txt ) & done
There's no need for a semi-colon at the end because the closing parenthesis marks the end of the statement too so we can drop it.
It can be a bit tricky to write all of this first time and get it all right so there are various little tricks you can do while you are trying. Firstly write protect our starting files, we don't want to overwrite them by mistake:
chmod -w *
In the for loop I would create an expression that just produces one result. So you could try either of these:
for file in `ls | head -1`
for file in MRN.ear
Also you want to start from a clean slate each time, so remove anything with an underscore in it or anything ending with .txt
:
rm -rf *_* *.txt ; for file in `ls | head -1`
When we think we have got it right then remove the |head -1
and run it for real.
I've talked it through in terms of the mental thought processes behind building the command so it has taken a bit longer to go through it. When you work in this environment, it's not long before you start to think in terms of running commands together using the background with lots of piping to get what you want. It becomes second nature, you can do some incredible things. Sometimes those lines will go into a bigger bash program or used in a scheduled task, but most of the time, surprisingly, they are just thrown away because that thing you wanted to do is now done and you won't have to do it again. It's not even worth putting it in a file!!!
Further to my article Import Firefox Password Manager into Lastpass, I needed to do the same for the passwords stored on my mobile phone.
On my Android phone, load Chrome and go to Settings > Passwords. Click the 3-dot menu and then Export passwords. It'll ask for your password and confirmation then invite you to share the file. I used Bluetooth to transfer the file to my Mac. It named the file .com.google.Chrome.YmmVuO
where presumably the YmmVuO is the profile identifier. The dot at the front of the file name meant that it was invisible in Finder so it was back to the command line. Same procedure as before only we are converting The Chrome password CSV file which looks like this:
name,url,username,password
,android://nhugfghjkiu7y6grbh_yhg5f4d3d5fgthujo8hy7gytr_jhbggb==@com.example/,mrn@example.com,
example.com,https://example.com/login.php,mrn@example.com,armadillo
Follow the same steps as before and then apply the magic incantation:
d="Imported on `date`"
sed "s/^/$d,Imported,/" .com.google.Chrome.YmmVuO | \
sed "s/^$d,Imported,name/notes,folder,name/" \
> Chrome.YmnVuO_lastpass.csv
This converts it into the Lastpass CSV ready to import.
notes,folder,name,url,username,password
Imported on Thu 27 Jun 2019 17:03:29 BST,Imported,,android://nhugfghjkiu7y6grbh_yhg5f4d3d5fgthujo8hy7gytr_jhbggb==@com.example/,mrn@example.com,
Imported on Thu 27 Jun 2019 17:03:29 BST,Imported,example.com,https://example.com/login.php,mrn@example.com,armadillo
Now just follow the steps from Import CSV into Lastpass steps.