fish shell: how to append an element to an array - fish

I'm trying to append an element to an array.
What I tried is:
for i in (seq 10)
set children $children $line[$i]
end
but that does not add a new element. It creates a single variable containing all of children then a space and $line[$i].

Using fish version 2.7.1-1113-ge598cb23 (3.0 pre-alpha) you can use set -a (append) or set -p (prepend).
set -l array "tiny tim" bob
set -l children joe elias matt
echo $children
for i in (seq 2)
set -a children $array[$i]
end
echo $children
Output:
joe elias matt
joe elias matt tiny tim bob
You could also use the string command which should work on most recent versions of fish.
set -l array "tiny tim" bob
set -l children joe elias matt
echo $children
for i in (seq 2)
set children (string join " " $children $array[$i])
end
echo $children
Output:
joe elias matt
joe elias matt tiny tim bob

Related

Treat Two Columns as One

Sample Text:
$ cat X
Birth Death Name
02/28/42 07/03/69 Brian Jones
11/27/42 09/18/70 Jimi Hendrix
11/19/43 10/04/70 Janis Joplin
12/08/43 07/03/71 Jim Morrison
11/20/46 10/29/71 Duane Allman
After Processing With Perl, column & sed:
$ perl -lae 'print "$F[2]_$F[3] $F[0]"' X | column -t | sed 's/_/ /g'
Name Birth
Brian Jones 02/28/42
Jimi Hendrix 11/27/42
Janis Joplin 11/19/43
Jim Morrison 12/08/43
Duane Allman 11/20/46
This is the exact output I want. But the issue is, I do not want to use column -t | sed 's/_/ /g' at the end.
My intuition is that this can be done only with perl oneliner (without the need of sed or column).
Is it possible? How can I do that?
P.S. I have an awk solution (awk '{print $3"_"$4" "$1}' X | column -t | sed 's/_/ /g')as well for this exact same result. However, I am looking for a perl only solution.
One way
perl -wlnE'say join " ", (split " ", $_, 3)[-1,0]' input.txt
This limits the split to three terms -- first two fields obtained by normally splitting by the given pattern, and then the rest, here comprising the name.
It won't line up nicely as in the shown output.
If the proper alignment is a must, then there's more to do since one must first see the whole file in order to know what the field width should be. Then the "one"-liner (command-line program) is
perl -MList::Util=max -wlne'
push #recs, [ (split " ", $_, 3)[-1,0] ];
END {
$m = max map { length $_->[0] } #recs;
printf("%-${m}s %s\n", #$_) for #recs
}' input.txt
If an apriori-set field width is acceptable, as brought up in a comment, we can do
perl -wlne'printf "%-20s %s\n", (split " ", $_, 3)[-1,0]' input.txt
The saving grace for the obvious short-coming here -- what with names that are longer? -- is that it is only those particular lines that will be out of order.
See if following one liner will be an acceptable solution
perl -ne "/(\S+)\s+\S+\s+(.*)/, printf \"%-13s %s\n\",$2,$1" birth_data.dat
Input birth_data.dat
Birth Death Name
02/28/42 07/03/69 Brian Jones
11/27/42 09/18/70 Jimi Hendrix
11/19/43 10/04/70 Janis Joplin
12/08/43 07/03/71 Jim Morrison
11/20/46 10/29/71 Duane Allman
Output
Name Birth
Brian Jones 02/28/42
Jimi Hendrix 11/27/42
Janis Joplin 11/19/43
Jim Morrison 12/08/43
Duane Allman 11/20/46

what is the best way to extract filled data from a static form?

I have some federal pdf forms with filled data init. Lets say for example i765 and I have the data of this form available in a text format, with duly filled in details. How can I extract the data from this form with minimum parsing. Lets say how can write a script that identifies "difference" , which in itself is nothing but the filled information.
For eg: if a line contains..
SSN: (Whitespace) and the actual filled in form has SSN: ABC!##456
so the filled in information is nothing but ABC!##456 which just a difference between the strings . Is there a known approach that i can follow. Any pointers are much appreciated.
If we are talking about Linux Tools then you could try various solutions , like:
$ join -t"=" -a1 -o 0,2.2 <(sort emptyform) <(sort filledform) # "=" is used as delimiter
Or even awk without sorting requirements:
$ awk 'BEGIN{FS=OFS="="}NR==FNR{a[$1]=$2;next}{if ($1 in a) {print;delete a[$1]}} \
END{print "\n Missing fields:";for (i in a) print i,a[i]}' empty filled
Testing:
cat <<EOF >empty
Name=""
Surname=""
Age=""
Address=""
Kids=""
Married=""
EOF
cat <<EOF >filled
Name="George"
Surname="Vasiliou"
Age="42"
Address="Europe"
EOF
join -t"=" -a1 -o 0,2.2 <(sort empty) <(sort filled)
#Output:
Address="Europe"
Age="42"
Kids=
Married=
Name="George"
Surname="Vasiliou"
awk output
awk 'BEGIN{FS=OFS="="}NR==FNR{a[$1]=$2;next}{if ($1 in a) {print;delete a[$1]}} \
END{print "\nnot completed fields:";for (i in a) print i,a[i]}' empty filled
Name="George"
Surname="Vasiliou"
Age="42"
Address="Europe"
not completed fields:
Married=""
Kids=""
Especially in awk if you remove the print from {if ($1 in a) {print;delete a[$1]}} the END section will print out for you only the missing fields.
Another alternative with a nice visual interface is with diff utility:
$ diff -y <(sort empty) <(sort filled)
Address="" | Address="Europe"
Age="" | Age="42"
Kids="" | Name="George"
Married="" | Surname="Vasiliou"
Name="" <
Surname="" <

how to separate a 10-digit phone number into two parts

For example, I get a phone number like 9191234567, how could I separate it into two parts, with the first part containing the three leading digits 919 and the other part containing the rest seven digits 1234567? After that, I want to store these two parts into two different variables in ksh.
I don't know if this could be done with sed?
You could try this :
echo "9191234567" | sed 's/^\([0-9]\{3\}\)\([0-9]\{7\}\)$/\1 \2/'
To store each part in a separate variable, you could do this :
phone="9191234567"
part1=$(echo $phone | sed 's/^\([0-9]\{3\}\)[0-9]\{7\}$/\1/')
part2=$(echo $phone | sed 's/^[0-9]\{3\}\([0-9]\{7\}\)$/\1/')
Or even more concise :
read part1 part2 <<< $(echo "9191234567" | sed 's/^\([0-9]\{3\}\)\([0-9]\{7\}\)$/\1 \2/')
cut should work
echo '9191234567' | cut --characters 1-3,4- --output-delimiter ' '
919 1234567
echo 9191234567 | sed 's/^\([1-9]\{3\}\)\([1-9]*\)/\1\-\2/'
Will print 919-1234567
Using bash
$ phone=9191234567
$ regex="^([0-9]{3})([0-9]{7})$"
$ [[ $phone =~ $regex ]] && part1="${BASH_REMATCH[1]}" && part2="${BASH_REMATCH[2]}"
$ echo $part1
919
$ echo $part2
1234567
Pure ksh, take number, print as two separate strings, separated by white space.
function split_at_third {
typeset number=$1 a b
b=${number#???} && a=${number%$b}
print $a $b
}

sed/awk/cut/grep - Best way to extract string

I have a results.txt file that is structured in this format:
Uncharted 3: Javithaxx l Rampant l Graveyard l Team Deathmatch HD (D1VpWBaxR8c)
Matt Darey feat. Kate Louise Smith - See The Sun (Toby Hedges Remix) (EQHdC_gGnA0)
The Matrix State (SXP06Oax70o)
Above & Beyond - Group Therapy Radio 014 (guest Lange) (2013-02-08) (8aOdRACuXiU)
I want to create a new file extracting the youtube URL ID specified in the last characters in each line line "8aOdRACuXiU"
I'm trying to build a URL like this in a new file:
http://www.youtube.com/watch?v=8aOdRACuXiU&hd=1
Note, I appended the &hd=1 to the string that I am trying to be replaced. I have tried using Linux reverse and cut but reverse or rev munges my data. The hard part here is that each line in my text file will have entries with parentheses and I only care about getting the data between the last set of parentheses. Each line has a variable length so that isn't helpful either. What about using grep and .$ for the end of the line?
In summary, I want to extract the youtube ID from results.txt and export it to a new file in the following format: http://www.youtube.com/watch?v=8aOdRACuXiU&hd=1
Using awk:
awk '{
v = substr( $NF, 2, length( $NF ) - 2 )
printf "%s%s%s\n", "http://www.youtube.com/watch?v=", v, "&hd=1"
}' infile
It yields:
http://www.youtube.com/watch?v=D1VpWBaxR8c&hd=1
http://www.youtube.com/watch?v=EQHdC_gGnA0&hd=1
http://www.youtube.com/watch?v=SXP06Oax70o&hd=1
http://www.youtube.com/watch?v=8aOdRACuXiU&hd=1
$ sed 's!.*(\(.*\))!http://www.youtube.com/watch?v=\1\&hd=1!' results.txt
http://www.youtube.com/watch?v=D1VpWBaxR8c&hd=1
http://www.youtube.com/watch?v=EQHdC_gGnA0&hd=1
http://www.youtube.com/watch?v=SXP06Oax70o&hd=1
http://www.youtube.com/watch?v=8aOdRACuXiU&hd=1
Here, .*(\(.*\)) looks for the last occurrence of a pair of parentheses, and captures the characters inside those parentheses. The captured group is then inserted into the URL using \1.
Using a perl one-liner :
perl -lne 'printf "http://www.youtube.com/watch?v=%s&hd=1\n", $& if /[^\(]+(?=\)$)/' file.txt
Or multi-line version :
perl -lne '
printf(
"http://www.youtube.com/watch?v=%s&hd=1\n",
$&
) if /[^\(]+(?=\)$)/
' file.txt

zenity list and for loop

for i in $(seq 1 10); do
echo 'bla bla'
echo 'xxx'
echo $i
done | select=$(zenity --list --title="title" --text="text" --column="X" --column="Y" --column="Z");
I try to create a checklist with zenity, my problem is that $select is always empty.
I try to do it in few other ways, like this one:
for i in $(seq 1 10)
do
x="bla bla"
y="xxx"
z="$i"
table="$table '$x' '$y' '$z'"
done
eval zenity --list --title="title" --text="text" --column="X" --column="Y" --column="Z" $table
In this way the $select variable isn't empty but if there are spaces in some variable (like $x for example) zenity split it to 2 (or more) columns.
I need other solution or any fix for my code(s)?
Thanks!
You can try this other approach:
#!/bin/bash
for i in $(seq 1 10)
do
echo "bla bla"
echo "xxx"
echo "$i"
done | zenity --list --title="title" --text="text" --column="X" --column="Y" --column="Z"
Each line populate the table from the first column to the last, and then again on a new row, until the input stream ends.