On "Linux Mint 16 Petra" i type this command :
zenity --list --column "test" a b c
I select the item 'a', then the returnning value is randomly
a or a|a
How do you explain this ? is it a zenity bug ?
How to get only 'a' ?
Regards.
It is a pretty annoying bug. Not the first one this year too.
open=$(find "${#}" -iname "$string" | zenity --list --title "Search results" --text "Please select file or directory to open:" --width 800 --height 600 --column "Files")
work-around:
opens=$(echo $open | cut -d "|" -f2)
When you select "a" with mouse double click (or with the enter key on keyboard), the value is "a|a". When you select it and press "Ok", the value is "a".
I don't know exactly why.
A simple workaround could be :
TMP=$(zenity --list --column "test" a b c) # Save the returned value in TMP
VAL=${TMP:0:1} # Keep the first character of TMP and put it in VAL
echo $VAL # VAL = "a", "b" or "c"
Print every value in a | separated list : zenity --list --print-column=ALL (...) and get the whole selected row.
Related
I am just learning bash scripting and commands and i need some help with this assignment.
I have txt file that contains the following text and i need to:
Extract guest name ( 1.1.1 ..)
Sum guest result and output the guest name with result.
I used sed with simple regex to extract out the name and the digits but i have no idea about how to summarize the numbers becuase the guest have multiple lines record as you can see in the txt file. Note: i can't use awk for processing
Here is my code:
cat file.txt | sed -E 's/.*([0-9]{1}.[0-9]{1}.[0-9]{1}).*([0-9]{1})/\1 \2/'
And result is:
1.1.1 4
2.2.2 2
1.1.1 1
3.3.3 1
2.2.2 1
Here is the .txt file:
Guest 1.1.1 have "4
Guest 2.2.2 have "2
Guest 1.1.1 have "1
Guest 3.3.3 have "1
Guest 2.2.2 have "1
and the output should be:
1.1.1 = 5
2.2.2 = 3
3.3.3 = 1
Thank you in advance
I know your teacher wont let you use awk but, since beyond this one exercise you're trying to learn how to write shell scripts, FYI here's how you'd really do this job in a shell script:
$ awk -F'[ "]' -v OFS=' = ' '{sum[$2]+=$NF} END{for (id in sum) print id, sum[id]}' file
3.3.3 = 1
2.2.2 = 3
1.1.1 = 5
and here's a bash builtins equivalent which may or may not be what you've covered in class and so may or may not be what your teacher is expecting:
$ cat tst.sh
#!/bin/env bash
declare -A sum
while read -r _ id _ cnt; do
(( sum[$id] += "${cnt#\"}" ))
done < "$1"
for id in "${!sum[#]}"; do
printf '%s = %d\n' "$id" "${sum[$id]}"
done
$ ./tst.sh file
1.1.1 = 5
2.2.2 = 3
3.3.3 = 1
See https://www.artificialworlds.net/blog/2012/10/17/bash-associative-array-examples/ for how I'm using the associative array. It'll be orders of magnitude slower than the awk script and I'm not 100% sure it's bullet-proof (since shell isn't designed to process text there are a LOT of caveats and pitfalls) but it'll work for the input you provided.
OK -- since this is a class assignment, I will tell you how I did it, and let you write the code.
First, I sorted the file. Then, I read the file one line at a time. If the name changed, I printed out the previous name and count, and set the count to be the value on that line. If the name did not change, I added the value to the count.
Second solution used an associative array to hold the counts, using the guest name as the index. Then you just add the new value to the count in the array element indexed on the guest name.
At the end, loop through the array, print out the indexes and values.
It's a lot shorter.
I'm trying to do the following:
Check the cell for N/A or No; if it has either of these then it should output N/A or No
Check the cell for either £ or € or Yes; If it has one of these then it would continue to step 3. If it has $ then it should repeat the same input as the output.
Extract currency from cell using: REGEXEXTRACT(A1, "\$\d+") or REGEXEXTRACT(A1, "\£\d+") (I assume that's the best way)
Convert it to $ USD using GoogleFinance("CURRENCY:EURUSD") or GoogleFinance("CURRENCY:GBPUSD")
Output the original cell but replacing the extracted currency from step 3 with the output from step 4.
Examples: (Original --> Output)
N/A --> N/A
No --> No
Alt --> Alt
Yes --> Yes
Yes £10 --> Yes $12.19
Yes £10 per week --> Yes $12.19 per week
Yes €5 (Next) --> Yes $5.49 (Next)
Yes $5 22 EA --> Yes $5 22 EA
Yes £5 - £10 --> Yes $5.49 - $12.19
I am unable to get a working IF statement working, I could do this in normal code but can't work it out for spreadsheet formulas.
I've tried modifying #Rubén's answer lots of times to including the N/A as it's not the Sheets error, I also tried the same for making any USD inputs come out as USD (no changes) but I really can't get the hang of IF/OR/AND in Excel/Google Sheets.
=ArrayFormula(
SUBSTITUTE(
A1,
OR(IF(A1="No","No",REGEXEXTRACT(A1, "[\£|\€]\d+")),IF(A1="N/A","N/A",REGEXEXTRACT(A1, "[\£|\€]\d+"))),
IF(
A1="No",
"No",
TEXT(
REGEXEXTRACT(A1, "[\£|\€](\d+)")*
IF(
"€"=REGEXEXTRACT(A1, "([\£|\€])\d+"),
GoogleFinance("CURRENCY:EURUSD"),
GoogleFinance("CURRENCY:GBPUSD")
),
"$###,###"
)
)
)
)
The above, I tried to add an OR() before the first IF statement to try and include N/A as an option, in the below I tried it as you can see below in various different ways (replace line 4 with this)
IF(
OR(
A1="No",
"No",
REGEXEXTRACT(A1, "[\£|\€]\d+");
A1="No",
"No",
REGEXEXTRACT(A1, "[\£|\€]\d+")
)
)
But that doesn't work either. I thought using ; was a way to separate the OR expressions but apparently not.
Re: Rubén's latest code 16/10/2016
I've modified it to =ArrayFormula(
IF(NOT(ISBLANK(A2)),
IF(IFERROR(SEARCH("$",A2),0),A2,IF(A2="N/A","N/A",IF(A2="No","No",IF(A2="Alt","Alt",IF(A2="Yes","Yes",
SUBSTITUTE(
A2,
REGEXEXTRACT(A2, "[\£|\€]\d+"),
TEXT(
REGEXEXTRACT(A2, "[\£|\€](\d+)")
*
VLOOKUP(
REGEXEXTRACT(A2, "([\£|\€])\d+"),
{
{"£";"€"},
{GoogleFinance("CURRENCY:GBPUSD");GoogleFinance("CURRENCY:EURUSD")}
},
2,0),
"$###,###"
)
)
)))))
,"")
)
This fixes:
Blank cells no longer throw #N/A
Yes only cells no longer throw #N/A
Added another text value Alt
Changes the format of the currency to 0 decimal places rather than my original request of 2 decimal places.
As you can see in the image below the two red cells aren't quite correct as I never thought of this scenario, the second of the two values is staying in it's input form and not being converted to USD.
Direct answer
Try
=ArrayFormula(
IF(IFERROR(SEARCH("$",A1:A6),0),A1:A6,IF(A1:A6="N/A","N/A",IF(A1:A6="No","No",
SUBSTITUTE(
A1:A6,
REGEXEXTRACT(A1:A6, "[\£|\€]\d+"),
TEXT(
REGEXEXTRACT(A1:A6, "[\£|\€](\d+)")
*
VLOOKUP(
REGEXEXTRACT(A1:A6, "([\£|\€])\d+"),
{
{"£";"€"},
{GoogleFinance("CURRENCY:GBPUSD");GoogleFinance("CURRENCY:EURUSD")}
},
2,0),
"$###,###.00"
)
)
)))
)
Result
+---+------------------+---------------------+
| | A | B |
+---+------------------+---------------------+
| 1 | N/A | N/A |
| 2 | No | No |
| 3 | Yes £10 | Yes $12.19 |
| 4 | Yes £10 per week | Yes $12.19 per week |
| 5 | Yes €5 (Next) | Yes $5.49 (Next) |
+---+------------------+---------------------+
Explanation
OR function
Instead or using OR function, the above formula use nested IF functions.
REGEXTRACT
Instead of using a REGEXEXTRACT function for each currency symbol, a regex OR operator was used. Example
REGEXEXTRACT(A1:A6, "[\£|\€]\d+")
Three regular expressions were used,
get currency symbol and the amount [\£|\€]\d+
get the amount [\£|\€](\d+)
get the currency symbol [(\£|\€])\d+
Currency conversion
Instead of using nested IF to handle currency conversion rates, VLOOKUP and array is used. This could be make easier to maintain the formula assuming that more currencies could be added in the future.
I have a phone book file rubrica.txt, which contains records (name, second name, phone number, telephone number, date, date in seconds) on each line like that (each entry is separated by a space):
andrea mantovani 3476589456 0451234567 2016/05/16 1463419858190456946
marco verratti 1265897654 3057634987 2016/05/16 1463419948782978926
zlatan ibrahimovic 2937485929 1938472639 2016/05/16 1463420078149548084
cesc fabregas 5641287659 3456789123 2016/05/16 1463420324574207170
andrea mantovani 3402948586 0459687124 2016/05/17 1463500810082293135
marco rossi 3951326586 0458793540 2016/05/17 1463500836814967504
I want to view on output all contacts that have been added after a date inserted by me.
At first I read the date that I want and convert it to seconds with the following script:
echo "Digit the date"
read date_jap #read a date(yyyy/mm/dd)
data_sec=$(date +%s -d $data_jap) #convert the date in sec
This part of code function. I explain that to be more clear.
I don't know how can I compare this date with the date (the last entry) in file rubrica.txt.
I used:
cat $RUBRICA | awk '/$data_sec < \6/ { print }'
to display all contacts whose date in seconds in the field 6 of the line (example taking my file at the first line: 1463419858190456946) is greater than date_sec.
$data_sec < \6 I know is incorrect. I must fix it.
Let's assume your date in seconds is the value of the third record and assign that:
data_sec=1463420078149548084
Now we get this value into awk using -v, then compare the sixth field to it:
$ awk -v mydate="$data_sec" '$6 > mydate' rubrica.txt
cesc fabregas 5641287659 3456789123 2016/05/16 1463420324574207170
andrea mantovani 3402948586 0459687124 2016/05/17 1463500810082293135
marco rossi 3951326586 0458793540 2016/05/17 1463500836814967504
If the expression $6 > mydate evaluates to true, the record gets printed.
I have the following data:
====> START LOG for Background Process: HRBkg Hello on 2013/09/27 23:20:20 Log Level 3 09/27 23:20:20 I Background process is using
processing model #: 3 09/27 23:20:23 I 09/27 23:20:23 I --
Started Import for External Key
====> START LOG for Background Process: HRBkg Hello on 2013/09/30 07:31:07 Log Level 3 09/30 07:31:07 I Background process is using
processing model #: 3 09/30 07:31:09 I 09/30 07:31:09 I --
Started Import for External Key
I need to extract the remaining file contents after the LAST match of ====> START LOG.....
I have tried numerous times to use sed/awk, however, I can not seem to get awk to utilize a variable in my regular expression. The variable I was trying to include was for the date (2013/09/30) since that is what makes the line unique.
I am on an HP-UX machine and can not use grep -A.
Any advice?
There's no need to test for a specific time just to find the last entry in the file:
awk '
BEGIN { ARGV[ARGC] = ARGV[ARGC-1]; ARGC++ }
NR == FNR { if (/START LOG/) lastMatch=NR; next }
FNR == lastMatch { found=1 }
found
' file
This might work for you (GNU sed):
a=2013/09/30
sed '\|START LOG.*'"$a"'|{h;d};H;$!d;x' file
This will return your desired output.
sed -n '/START LOG/h;/START LOG/!H;$!b;x;p' file
If you have tac available, you could easily do..
tac <file> | sed '/START LOG/q' | tac
Here is one in Python:
#!/usr/bin/python
import sys, re
for fn in sys.argv[1:]:
with open(fn) as f:
m=re.search(r'.*(^====> START LOG.*)',f.read(), re.S | re.M)
if m:
print m.group(1)
Then run:
$ ./re.py /tmp/log.txt
====> START LOG for Background Process: HRBkg Hello on 2013/09/30 07:31:07 Log Level 3
09/30 07:31:07 I Background process is using processing model #: 3
09/30 07:31:09 I
09/30 07:31:09 I -- Started Import for External Key
If you want to exclude the ====> START LOGS.. bit, change the regex to:
r'.*(?:^====> START LOG.*?$\n)(.*)'
For the record, you can easily match a variable against a regular expression in Awk, or vice versa.
awk -v date='2013/09/30' '$0 ~ date {p=1} p' file
This sets p to 1 if the input line matches the date, and prints if p is non-zero.
(Recall that the general form in Awk is condition { actions } where the block of actions is optional; if omitted, the default action is to print the current input line.)
This prints the last START LOG, it set a flag for the last block and print it.
awk 'FNR==NR { if ($0~/^====> START LOG/) f=NR;next} FNR>=f' file file
You can use a variable, but if you have another file with another date, you need to know the date in advance.
var="2013/09/30"
awk '$0~v && /^====> START LOG/ {f=1}f' v="$var" file
====> START LOG for Background Process: HRBkg Hello on 2013/09/30 07:31:07 Log Level 3
09/30 07:31:07 I Background process is using processing model #: 3
09/30 07:31:09 I
09/30 07:31:09 I -- Started Import for External Key
With GNU awk (gawk) or Mikes awk (mawk) you can set the record separator (RS) so that each record will contain a whole log message. So all you need to do is print the last one in the END block:
awk 'END { printf "%s", RS $0 }' RS='====> START LOG' infile
Output:
====> START LOG for Background Process: HRBkg Hello on 2013/09/30 07:31:07 Log Level 3
09/30 07:31:07 I Background process is using processing model #: 3
09/30 07:31:09 I
09/30 07:31:09 I -- Started Import for External Key
Answer in perl:
If your logs are in assume filelog.txt.
my #line;
open (LOG, "<filelog.txt") or "die could not open filelog.tx";
while(<LOG>) {
#line = $_;
}
my $lengthline = $#line;
my #newarray;
my $j=0;
for(my $i= $lengthline ; $i >= 0 ; $i++) {
#newarray[$j] = $line[$i];
if($line[$i] =~ m/^====> START LOG.*/) {
last;
}
$j++;
}
print "#newarray \n";
I'm trying to map a drive letter using this line of code which will give me a list of drives available from d to z.
ls function:[d-z]: -n | ? { !(test-path $_) }
I'd like to then pick the last letter, not random, from the list. How would I go about doing that? New to Powershell, thanks for the help.
You can use Select-Object -Last 1 at the end of that pipeline.
you can just start at the back of the list and go up.
last item: $array[-1]
Second to last: $array[-2]
and so on.
If you look for a much more verbose, but (in my opinion) readable-improved version:
# Get all drives which are used (unavailable)
# Filter for the "Name" property ==> Drive letter
$Drives = (Get-PSDrive -PSProvider FileSystem).Name
# Create an array of D to Z
# Haven't found a more elegant version...
$Letters = [char[]]([char]'D'..[char]'Z')
# Filter out, which $Letters are not in $Drives (<=)
# Again, filter for their letter
$Available = (Compare-Object -ReferenceObject $Letters -DifferenceObject $Drives | Where {$_.SideIndicator -eq "<="}).InputObject
# Get the last letter
$LastLetter = $Available[-1]
Try this:
ls function:[d-z]: -n|?{!(test-path $_)} | Select-Object -Last 1
Another option that doesn't require trying all paths from D-Z is to parse Get-Psdrive. Here's an example:
$lettersInUse = Get-Psdrive | ? { $_.Name.Length -eq 1 } | % { $_.Name }
$lastDriveLetter = [Char]'Z'
while ($lettersInUse -contains $lastDriveLetter) {
$lastDriveLetter = [Char]($lastDriveLetter - 1)
}
$lastDriveLetter
In case you have an array
$newArray = #(git tag --list)
$lastmember = $newArray[$newArray.Count – 1]
In case you have a list
$newArray | Select-Object -Last 1