To find out a way to loop through all elements in an array consisting of more than one element, it’s easy.
$ for f in {"hello","world"}; do echo $f; done
hello
world
When I try to take away the second element in the above array so that
it becomes an array consisting in one single element, then I get
{hello}
instead of hello
.
$ for f in {"hello"}; do echo $f; done
{hello}
How can one get back an output consistent with the case of arrays consisting of multiple elements?
This problem seems nonsense—loops are supposed to do repetitive tasks. If the loop has only one iteration, then we can directly type in the command, instead of adapting it into a loop and setting up the scope of the loop.
Nevertheless, if one converts multiple lines of short texts into one
long single line with xargs
, then the items will be separated by
white spaces. This won’t work with the above for loop. To change
the delimiter from white space to comma, one may use paste -d, -s
.
Syntax | Meaning |
---|---|
-d, |
Use , as the delimiter. |
-s |
Without this flag, $1 and $2 are displayed in parallel. |
Surely, there are other tools to do this, such as sed
. However, I
think that paste -d, -s
should be the simplest way to do this.
Note that the white space character between the two flags are
important. Otherwise, this command won’t work.
Without prior knowledge of the text to be processed, it’s possible
that the output of paste -d, -s
consists of only one item. This
single case is easy to deal with, even though the handling may be a
bit different from the case of multiple elements. However, if the
syntax for the command that handles the output of paste -d, -s
isn’t exactly the same in the case of one single element and the
case of multiple elements, then we need to look at the content and
make manual judgement–this is tedious and error-prone.
In the problem posed in the previous section, if the list in the for loop has only one item, then we need to do something different from a list having two or more items. If we observe this difference with our naked eyes, the whole process will lack efficiency.
To solve this problem, we seek an unified approach. In other words, I try to change the syntax of the above for loop so that the for loop will work for any one of these two cases.
The first step is needed if in the array, there exists an element having two or more words separated by a white space; the second step is needed for an array with one single element.
$ for f in {"hello world",}; do echo $f; done
hello world
As the number of steps increases, the difficulty of constructing a one-line command to do the thing rises tremendously. It’s possible that a shell script is easier to write. By searching “bash array tutorial” on Google, I got a tutorial on the Geek Stuff in the first search result.
1
2
3
4
5
6
#!/bin/bash
arr=("hello")
for f in ${arr[@]}; do
echo $f
done
Knowing some regular expressions in Vim, I hope to apply these concepts to Perl so that I can search and replace some simple strings directly in base without having to open the editor.
As a Vim user, the class of special characters in Perl is more
natural than that of sed
.
In the previous post, the list of Git commit messages containing
the string “HTTPS” is the main focus. However, the alignment of this
list isn’t good: in the column representing the day, the data can be
either one or two digit. Though I can still extract information with
awk '{print $[col_num]}'
, it’s better to fix the alignment.
$ git log -2 --grep="HTTPS" --pretty="%h %cd %s"
7400582 Sun Mar 20 20:19:47 2016 +0800 Updated my Rakefile with HTTPS
b6f4f1f Mon Feb 8 00:45:02 2016 +0800 A new article about Flair, Octopress and HTTPS
Searching “perl intro” online, one can easily find some basic Perl scripts. I tried to issue some simple one-line Perl command to save time, but I couldn’t easily find them. Thanks to a webpage by Philippe Bruhat, I managed to starting using Perl. I jot them down here.
$ perl -e 'print "hello \n"' # single quote outside
hello
$ perl -e "\$str='abc'; print \$str;" # escape $, no EOL
abc
$ perl -e "$str='test'; print $str.'\n';" # not desired
test\n
$ perl -e '$str="test"; print $str."\n";' # want newlne
test
The -e
flag above stands for “execute”.
Unluckily, I didn’t know how to use system()
nor backticks to pass
output of a command into Perl. After trying a few search keywords,
“perl oneline read command output” worked best for me. It was quite
uncommon that I found the eighth result useful. In the article
Perl One-liners, I found out the answer.
$ for (( i = 1; i <= 10; i++ )); do
echo $i
done | perl -e 'while (<>) {s/(?<!\d)\d{1}(?!\d)/0$&/; print $_}'
01
02
03
04
05
06
07
08
09
10
In fact, the flag -n
can be used to replace the while (<>) {...}
loop. The -p
flag has the function of -n
but also prints the
output. I learnt them from Git manual web page for git-log.
Combine the above observations together.
$ git log -2 --grep="HTTPS" --pretty="%h %cd %s" \
| perl -pe 's/(?<=\u\l\l )\d{1}(?= )/0$&/'
7400582 Sun Mar 20 20:19:47 2016 +0800 Updated my Rakefile with HTTPS
b6f4f1f Mon Feb 08 00:45:02 2016 +0800 A new article about Flair, Octopress and
HTTPS
$&
and
\b
in the replacement. This is the Perl counterpart of &
and
\<
or \>
in Vim respectively.git log
and git show
,
--name-only
: suppress the diff hunk--pretty=format:
display nothingformat
vs tformat
: t
stands for “terminator” (a.k.a. EOL)Each of each flags seems to be useless. Nevertheless, when combined together, they help extract the edited files in a particular commit.
Posting long commands in a blog entry
From the two codeblocks explaining the difference between format
and tformat
in the Git manual, I understand that it’s better to
end each line with a backslash, then continue with the command.
In bash, a >
is then automatically inserted at the beginning of
each line. This is carried from the shell to the source file of
the blog article by copy and paste. I used to think that it’s
good to keep this so that this and the Ubuntu font will give a
sense of reality to the reader. However, this also causes
inconvenience to those who want to try this command. From now on,
I won’t include this character anymore at the beginning of a
long command exceeding 80 characters. I will replace it with a
white space instead.