8. Building a Brash One-Liner
Get Ready to Be Brash
Be Flexible
1
2
3
4
5
6
7
8
9
| $ echo $(ls *.jpg)
$ bash -c 'ls *.jpg'
$ cat <(ls *.jpg)
$ find . -maxdepth 1 -type f -name \*.jpg -print
$ ls > tmp && grep '\.jpg$' tmp && rm -f tmp
$ paste <(echo ls) <(echo \*.jpg) | bash
$ bash -c 'exec $(paste <(echo ls) <(echo \*.jpg))'
$ echo 'monkey *.jpg' | sed 's/monkey/ls/' | bash
$ python -c 'import os; os.system("ls *.jpg")'
|
Think About Where to Start
1
2
3
4
| $ echo {A..Z} | awk '{print $(17)}'
Q
$ echo {A..Z} | sed 's/ //g' | cut -c17
Q
|
1
2
3
4
5
6
| $ echo 2021-{01..12}-01 | xargs -n1 date +%B -d
January
February
March
⋮
December
|
1
2
3
4
5
| $ ls | awk '{print "echo -n", $0, "| wc -c"}'
echo -n "animals.txt" | wc -c
echo -n "cartoon-mascots.txt | wc -c"
⋮
echo -n "zebra-stripes.txt | wc -c"
|
1
2
| $ ls | awk '{print "echo -n", $0, "| wc -c"}' | bash | sort -nr | head -n1
23
|
The general principle is the same: figure out your starting data and manipulate it to fit your needs.
Use command history and command-line editing.
- Don’t retype commands while you experiment. Use techniques from Chapter 3 to recall previous commands, tweak them, and run them.
Add echo to test your expressions.
- If you aren’t sure how an expression will evaluate, print it with echo beforehand to see the evaluated results on stdout.
Use ls or add echo to test destructive commands.
- If your command invokes rm, mv, cp, or other commands that might overwrite or remove files, place echo in front of them to confirm which files will be affected. (So, instead of executing rm, execute echo rm.) Another safety tactic is to replace rm with ls to list files that would be removed.
Insert a tee to view intermediate results.
$ paste <(seq -w 10 -1 3 | sed ‘s/(.*)/ch\1.asciidoc/’) \ |
<(seq -w 11 -1 4 | sed ‘s/(.*)/ch\1.asciidoc/’) \ |
| sed ‘s/^/mv /’ \ |
| bash |
$ ls ch*.asciidoc ch01.asciidoc ch04.asciidoc ch06.asciidoc ch08.asciidoc ch10.asciidoc ch02.asciidoc ch05.asciidoc ch07.asciidoc ch09.asciidoc ch11.asciidoc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
## Checking Matched Pairs of Files
```bash
$ ls
bald_eagle.jpg blue_jay.jpg cardinal.txt robin.jpg wren.jpg
bald_eagle.txt cardinal.jpg oriole.txt robin.txt wren.txt
$ ls *.jpg | cut -d. -f1
bald_eagle
blue_jay
cardinal
robin
wren
$ ls *.txt | cut -d. -f1
bald_eagle
cardinal
oriole
robin
wren
$ diff <(ls *.jpg | cut -d. -f1) <(ls *.txt | cut -d. -f1)
2d1
< blue_jay
3a3
> oriole
$ diff <(ls *.jpg | cut -d. -f1) <(ls *.txt | cut -d. -f1) \
| grep '^[<>]'
< blue_jay
> oriole
$ diff <(ls *.jpg | cut -d. -f1) <(ls *.txt | cut -d. -f1) \
| grep '^[<>]' \
| awk '/^</{print $2 ".jpg"} /^>/{print $2 ".txt"}'
blue_jay.jpg
oriole.txt
$ diff <(ls *.jpg | sed 's/\.[^.]*$//') \
<(ls *.txt | sed 's/\.[^.]*$//') \
| grep '^[<>]' \
| awk '/</{print $2 ".jpg"} />/{print $2 ".txt"}'
blue_jay.txt
oriole.jpg
yellow.canary.txt
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| $ ls *.{jpg,txt} \
| sed 's/\.[^.]*$//' \
| uniq -c
2 bald_eagle
1 blue_jay
2 cardinal
1 oriole
2 robin
2 wren
1 yellow.canary
$ ls *.{jpg,txt} \
| sed 's/\.[^.]*$//' \
| uniq -c \
| awk '/^ *1 /{print $2}'
blue_jay
oriole
yellow.canary
$ ls *.{jpg,txt} \
| sed 's/\.[^.]*$//' \
| uniq -c \
| awk '/^ *1 /{print $2 ".*"}'
blue_jay.*
oriole.*
yellow.canary.*
$ ls -1 $(ls *.{jpg,txt} \
| sed 's/\.[^.]*$//' \
| uniq -c \
| awk '/^ *1 /{print $2 ".*"}')
blue_jay.jpg
oriole.txt
yellow.canary.jpg
|
Generating a CDPATH from Your Home Directory
1
2
| $ (cd && ls -d */)
Family/ Finances/ Linux/ Music/ Work/
|
1
2
3
4
5
6
| $ (cd && ls -d */) | sed 's/^/$HOME\//g'
$HOME/Family/
$HOME/Finances/
$HOME/Linux/
$HOME/Music/
$HOME/Work/
|
1
2
3
4
5
6
| $ (cd && ls -d */) | sed 's@^@$HOME/@g'
$HOME/Family/
$HOME/Finances/
$HOME/Linux/
$HOME/Music/
$HOME/Work/
|
1
2
3
4
5
6
| $ (cd && ls -d */) | sed -e 's@^@$HOME/@' -e 's@/$@@'
$HOME/Family
$HOME/Finances
$HOME/Linux
$HOME/Music
$HOME/Work
|
1
2
| $ echo $(cd && ls -d */ | sed -e 's@^@$HOME/@' -e 's@/$@@')
$HOME/Family $HOME/Finances $HOME/Linux $HOME/Music $HOME/Work
|
1
2
3
4
| $ echo '$HOME' \
$(cd && ls -d */ | sed -e 's@^@$HOME/@' -e 's@/$@@') \
..
$HOME $HOME/Family $HOME/Finances $HOME/Linux $HOME/Music $HOME/Work ..
|
1
2
3
4
| $ echo '$HOME' \
$(cd && ls -d */ | sed -e 's@^@$HOME/@' -e 's@/$@@') \
.. \
| tr ' ' ':'
|
1
2
3
4
5
| $ echo 'CDPATH=$HOME' \
$(cd && ls -d */ | sed -e 's@^@$HOME/@' -e 's@/$@@') \
.. \
| tr ' ' ':'
CDPATH=$HOME:$HOME/Family:$HOME/Finances:$HOME/Linux:$HOME/Music:$HOME/Work:..
|
Generating Test Files
1
2
3
4
5
6
7
8
| $ shuf /usr/share/dict/words | head -n3
evermore
shirttail
tertiary
$ shuf /usr/share/dict/words | head -n3
interactively
opt
perjurer
|
1
2
| $ echo $RANDOM $RANDOM $RANDOM
7855 11134 262
|
1
2
3
4
| $ shuf -n $RANDOM /usr/share/dict/words | wc -l
9922
$ shuf -n $RANDOM /usr/share/dict/words | wc -l
32465
|
1
2
3
4
5
| $ pwgen
eng9nooG ier6YeVu AhZ7naeG Ap3quail poo2Ooj9 OYiuri9m iQuash0E voo3Eph1
IeQu7mi6 eipaC2ti exah8iNg oeGhahm8 airooJ8N eiZ7neez Dah8Vooj dixiV1fu
Xiejoti6 ieshei2K iX4isohk Ohm5gaol Ri9ah4eX Aiv1ahg3 Shaew3ko zohB4geu
⋮
|
1
2
| $ pwgen -N1 10
ieb2ESheiw
|
1
2
| $ echo $(pwgen -N1 10).txt
ohTie8aifo.txt
|
1
2
| $ mkdir -p /tmp/randomfiles && cd /tmp/randomfiles
$ shuf -n $RANDOM -o $(pwgen -N1 10).txt /usr/share/dict/words
|
1
2
3
4
5
6
7
8
| $ ls List the new file
Ahxiedie2f.txt
$ wc -l Ahxiedie2f.txt How many lines does it contain?
13544 Ahxiedie2f.txt
$ head -n3 Ahxiedie2f.txt Peek at the first few lines
saviors
guerillas
forecaster
|
1
2
3
| for i in {1..1000}; do
shuf -n $RANDOM -o $(pwgen -N1 10).txt /usr/share/dict/words
done
|
1
2
| $ echo 'shuf -n $RANDOM -o $(pwgen -N1 10).txt /usr/share/dict/words'
shuf -n $RANDOM -o $(pwgen -N1 10).txt /usr/share/dict/words
|
1
2
3
| $ echo 'shuf -n $RANDOM -o $(pwgen -N1 10).txt /usr/share/dict/words' | bash
$ ls
eiFohpies1.txt
|
1
2
3
4
5
6
7
8
| $ yes 'shuf -n $RANDOM -o $(pwgen -N1 10).txt /usr/share/dict/words' \
| head -n 1000 \
| bash
$ ls
Aen1lee0ir.txt IeKaveixa6.txt ahDee9lah2.txt paeR1Poh3d.txt
Ahxiedie2f.txt Kas8ooJahK.txt aoc0Yoohoh.txt sohl7Nohho.txt
CudieNgee4.txt Oe5ophae8e.txt haiV9mahNg.txt uchiek3Eew.txt
⋮
|
1
2
3
4
5
6
7
8
9
10
| # produce random images of size 100 x 100 pixels consisting of multicolored squares:
$ yes 'convert -size 8x8 xc: +noise Random -scale 100x100 $(pwgen -N1 10).png' \
| head -n 1000 \
| bash
$ ls
Bahdo4Yaop.png Um8ju8gie5.png aing1QuaiX.png ohi4ziNuwo.png
Eem5leijae.png Va7ohchiep.png eiMoog1kou.png ohnohwu4Ei.png
Eozaing1ie.png Zaev4Quien.png hiecima2Ye.png quaepaiY9t.png
⋮
$ display Bahdo4Yaop.png View the first image
|
Generating Empty Files
1
2
3
| $ mkdir /tmp/empties Create a directory for the files
$ cd /tmp/empties
$ touch file{01..1000}.txt Generate the files
|
1
2
3
4
5
| $ grep '^[a-z]*$' /usr/share/dict/words
a
aardvark
aardvarks
⋮
|
1
2
3
4
5
| $ grep '^[a-z]*$' /usr/share/dict/words | shuf | head -n1000
triplicating
quadruplicates
podiatrists
⋮
|
1
2
3
4
5
6
| $ grep '^[a-z]*$' /usr/share/dict/words | shuf | head -n1000 | xargs touch
$ ls
abases distinctly magnolia sadden
abets distrusts maintaining sales
aboard divided malformation salmon
⋮
|