Perl: suppress output of backtick when file not found - regex

In my code :
$status = `ls -l error*`;
It shows output : ls *error No such file or directory.
How can I suppress this message. I am interested in determining that the error files are generated or not. If yes, I need the list of files else ignore (without printing the message)

By running it like
$status = `ls -l error* 2> /dev/null`;
and suppressing the external command's output to standard error.
If you just need the file names (and not all the other info that ls's -l switch gives you), this can be accomplished in pure Perl with a statement like
#files = glob("error*");
if (#files == 0) {
... there were no files ...
} else {
... do something with files ...
}
and if you do need all the other info you get from ls -l ..., applying the builtin stat function to each file name can give you the same information.

Related

Popen giving some strange character in output when running multiple command in it

I write code to fetch the fragmented packet by using a unique Identification field from pcap file. So I run scripting command in my C++ program.
First tshark command will fetch all the identification field from the packet with the callID mentioned in the filter and the second one will fetch all the fragmented packet identification field in that pcap.
And awk command compare then and find the unique identification field present in both the tshark command output.
Command will be like---
cmd = (awk 'FNR==NR{a[$0]=1;next}($0 in a)' <((/usr/sbin/tshark -r
/data/traces/TRACES.pcap 'sip.Call-ID=="1-4740#10.133.0.1" or
sip.Call-ID=="57b116c-5b20924e-93dcd"' -T fields -e ip.id)
2>/dev/null) <((/usr/sbin/tshark -r /data/traces/TRACES.pcap
'ip.flags.mf==1' -T fields -e ip.id) 2>/dev/null)) 2>/dev/null
Reading data by
FILE * stream = popen(cmd.c_str(), "r");
if (!stream)
{
LOG_DEBUG("popen failed");
}
fflush(stream);
NOTE:: I tried with fflush and without fflush still giving me strange
character.
while(fgets(buffer, 40, stream) != NULL)
{
data = buffer;
result += data + '\n';
}
if(data.empty()) {
data = buffer;
result = data + '\0';
}
NOTE:: Tried with the system() command also but this also returns me a strange Character
OUTPUT will be like --> 0^_iÏO^?
I notice a strange thing that when I execute tshark command individually and save the output in a different file and then using awk command on that files then it will give the correct output.
And Command is correctly running in the terminal also.

How to write unix regular expression to select for specific files in a cp for-loop

I've got a directory with a bunch of files. Instead of describing the filenames and extensions, I'll just show you what is in the directory:
P01_1.atag P03_3.tgt P05_6.src P08_3.atag P10_5.tgt
P01_1.src P03_4.atag P05_6.tgt P08_3.src P10_6.atag
P01_1.tgt P03_4.src P06_1.atag P08_3.tgt P10_6.src
P01_2.atag P03_4.tgt P06_1.src P08_4.atag P10_6.tgt
P01_2.src P03_5.atag P06_1.tgt P08_4.src P11_1.atag
P01_2.tgt P03_5.src P06_2.atag P08_4.tgt P11_1.src
P01_3.atag P03_5.tgt P06_2.src P08_5.atag P11_1.tgt
P01_3.src P03_6.atag P06_2.tgt P08_5.src P11_2.atag
P01_3.tgt P03_6.src P06_3.atag P08_5.tgt P11_2.src
P01_4.atag P03_6.tgt P06_3.src P08_6.atag P11_2.tgt
P01_4.src P04_1.atag P06_3.tgt P08_6.src P11_3.atag
P01_4.tgt P04_1.src P06_4.atag P08_6.tgt P11_3.src
P01_5.atag P04_1.tgt P06_4.src P09_1.atag P11_3.tgt
P01_5.src P04_2.atag P06_4.tgt P09_1.src P11_4.atag
P01_5.tgt P04_2.src P06_5.atag P09_1.tgt P11_4.src
P01_6.atag P04_2.tgt P06_5.src P09_2.atag P11_4.tgt
P01_6.src P04_3.atag P06_5.tgt P09_2.src P11_5.atag
P01_6.tgt P04_3.src P06_6.atag P09_2.tgt P11_5.src
P02_1.atag P04_3.tgt P06_6.src P09_3.atag P11_5.tgt
P02_1.src P04_4.atag P06_6.tgt P09_3.src P11_6.atag
P02_1.tgt P04_4.src P07_1.atag P09_3.tgt P11_6.src
P02_2.atag P04_4.tgt P07_1.src P09_4.atag P11_6.tgt
P02_2.src P04_5.atag P07_1.tgt P09_4.src P12_1.atag
P02_2.tgt P04_5.src P07_2.atag P09_4.tgt P12_1.src
P02_3.atag P04_5.tgt P07_2.src P09_5.atag P12_1.tgt
P02_3.src P04_6.atag P07_2.tgt P09_5.src P12_2.atag
P02_3.tgt P04_6.src P07_3.atag P09_5.tgt P12_2.src
P02_4.atag P04_6.tgt P07_3.src P09_6.atag P12_2.tgt
P02_4.src P05_1.atag P07_3.tgt P09_6.src P12_3.atag
P02_4.tgt P05_1.src P07_4.atag P09_6.tgt P12_3.src
P02_5.atag P05_1.tgt P07_4.src P10_1.atag P12_3.tgt
P02_5.src P05_2.atag P07_4.tgt P10_1.src P12_4.atag
P02_5.tgt P05_2.src P07_5.atag P10_1.tgt P12_4.src
P02_6.atag P05_2.tgt P07_5.src P10_2.atag P12_4.tgt
P02_6.src P05_3.atag P07_5.tgt P10_2.src P12_5.atag
P02_6.tgt P05_3.src P07_6.atag P10_2.tgt P12_5.src
P03_1.atag P05_3.tgt P07_6.src P10_3.atag P12_5.tgt
P03_1.src P05_4.atag P07_6.tgt P10_3.src P12_6.atag
P03_1.tgt P05_4.src P08_1.atag P10_3.tgt P12_6.src
P03_2.atag P05_4.tgt P08_1.src P10_4.atag P12_6.tgt
P03_2.src P05_5.atag P08_1.tgt P10_4.src
P03_2.tgt P05_5.src P08_2.atag P10_4.tgt
P03_3.atag P05_5.tgt P08_2.src P10_5.atag
P03_3.src P05_6.atag P08_2.tgt P10_5.src
I have a file that is just outside of this directory that I need to copy to all of the files that end with "_1.src" inside the directory.
I'm working with unix in the Terminal app, so I tried writing this for loop, but it rejected my regular expression:
for .*1.src in ./
> do
> cp ../1.src
> done
I've only written regular expressions in Python before and have minimal experience, but I was under the impression that .* would match any combination of characters. However, I got the following error message:
-bash: `.*1.src': not a valid identifier
I then tried the same for loop with the following regular expression:
^[a-zA-Z0-9_]*1.src$
But I got the same error message:
-bash: `^[a-zA-Z0-9_]*1.src$': not a valid identifier
I tried the same regular expression with and without quotation marks, but it always gives the same 'not a valid identifier' error message.
Tested on Bash 4.4.12, the following is possible:
$ for i in ./*_1.src; do echo "$i" ; done
This will echo every file ending with _1.src to the screen, thus moving it will be possible as well.
$ mkdir tmp
$ for i in ./*_1.src; do mv "$i" tmp/.; done
I've tested with the following data:
$ touch P{1,2}{0,1,2}_{0..6}.{src,tgt,atag}
$ ls
P10_0.atag P10_5.src P11_3.tgt P12_2.atag P20_0.src P20_5.tgt P21_4.atag P22_2.src
P10_0.src P10_5.tgt P11_4.atag P12_2.src P20_0.tgt P20_6.atag P21_4.src P22_2.tgt
P10_0.tgt P10_6.atag P11_4.src P12_2.tgt P20_1.atag P20_6.src P21_4.tgt P22_3.atag
P10_1.atag P10_6.src P11_4.tgt P12_3.atag P20_1.src P20_6.tgt P21_5.atag P22_3.src
P10_1.src P10_6.tgt P11_5.atag P12_3.src P20_1.tgt P21_0.atag P21_5.src P22_3.tgt
P10_1.tgt P11_0.atag P11_5.src P12_3.tgt P20_2.atag P21_0.src P21_5.tgt P22_4.atag
P10_2.atag P11_0.src P11_5.tgt P12_4.atag P20_2.src P21_0.tgt P21_6.atag P22_4.src
P10_2.src P11_0.tgt P11_6.atag P12_4.src P20_2.tgt P21_1.atag P21_6.src P22_4.tgt
P10_2.tgt P11_1.atag P11_6.src P12_4.tgt P20_3.atag P21_1.src P21_6.tgt P22_5.atag
P10_3.atag P11_1.src P11_6.tgt P12_5.atag P20_3.src P21_1.tgt P22_0.atag P22_5.src
P10_3.src P11_1.tgt P12_0.atag P12_5.src P20_3.tgt P21_2.atag P22_0.src P22_5.tgt
P10_3.tgt P11_2.atag P12_0.src P12_5.tgt P20_4.atag P21_2.src P22_0.tgt P22_6.atag
P10_4.atag P11_2.src P12_0.tgt P12_6.atag P20_4.src P21_2.tgt P22_1.atag P22_6.src
P10_4.src P11_2.tgt P12_1.atag P12_6.src P20_4.tgt P21_3.atag P22_1.src P22_6.tgt
P10_4.tgt P11_3.atag P12_1.src P12_6.tgt P20_5.atag P21_3.src P22_1.tgt P10_5.atag
P11_3.src P12_1.tgt P20_0.atag P20_5.src P21_3.tgt P22_2.atag
Apparently, my previous answer didn't work. But this seems to:
$ for x in `echo ./P[01][012]_1.src`; do echo "$x"; done
./P01_1.src
./P02_1.src
So, when you run this echo alone, this pattern gets expanded into many names:
$ echo ./P[01][012]_1.src # note that the 'regex' is not enclosed in quotes
./P01_1.src ./P02_1.src
And then you can iterate over these names in a loop.
BTW, as noted in the comments, you don't even need that echo, so you can plug the pattern right into the loop:
for x in ./P[01][012]_1.src; do echo "$x"; done
Please correct me if your goal is something other than
"overwrite many existing files sharing a common suffix with the contents of a single file"
find /path/to/dest_dir -type f -name "*_1.src" |xargs -n1 cp /path/to/source_file
Note that without the -maxdepth 1 option, find will recurse through your destination directory.
Thanks to everyone; this is what ended up working:
for x in `echo ./P[0-9]*_1.src`
> do
> cp ../1.src "$x"
> done
This loop allowed me to copy the contents of the one file to all of the files in the subdirectory that ended with "_1.src"

Parsing files to populate placeholders with values

Background Info
I have a JS library which consists of many constructor functions. I am using grunt-concat & -uglify to compile these into a single file.
Each constructor has a readme.md file.
The library is used to create advertising banners. It is used by around 10 developers who create their own advertising templates within a folder Templates which use the library. The files are .xml files which also provide a CDATA tag where they can insert their JavaScript code.
Question
I would like to populate the readme files with a counter, so that the developers can see how popular a particular constructor is directly in its documentation.
Number of occurrences (<% occurrences %>)
What I've already done
I can get the number of occurrences by executing
find . -name "*.xml" -exec grep -e "new\Foo\.Bar" {} \; | wc -l
It would be great if I could grab this value and insert it to the readme file.
grunt.registerTask('count_occurrences', '', function () {
var exec = require('child_process').execSync;
var result = exec("find . -name "*.xml" -exec grep -e "new\Foo\.Bar" {} \; | wc -l", { encoding: 'utf8' });
grunt.log.writeln(result);
// Now write result to your README file
grunt.file.write("README.md", result);
});
or
You can use the grunt plugin called exec (https://github.com/jharding/grunt-exec) to execute cmd line functions, e.g. find.
You probably would want something like this in your GruntFile.js:
exec: {
count_occurrences: {
cmd: function() {
return 'find . -name "*.xml" -exec grep -e "new\Foo\.Bar" {} \; | wc -l';
}
}
}
Then call grunt exec:echo_name

Unix CLI script to rename folders using their pre-existing names

I have a directory with folder structure as follows:
-- DATA -- ABD 1231345 -- 01-08-12 // date in mm-dd-yy format
-- 03-09-12
-- 06-11-12
-- DEF 4859480 -- 02-10-12
-- 05-10-12
-- 07-10-12
I would like to batch rename this DATA folder as follows
-- DATA -- ABD 1231345 -- 2012_01_08 // date in yyyy_mm_dd format with underscore
-- 2012_03_09
-- 2012_06_11
-- DEF 4859480 -- 2012_02_10
-- 2012_05_10
-- 2012_07_10
Do you have a suggestion on how to accomplish using command line on Mac OSX / unix?
You could use a for loop and awk, parsing each file-name into your specified format and then mv to rename the original to the new name:
for dir in DATA/*; do \
pushd "$dir"; # change directory \
for file in *; do \
path=`echo $file | awk -F- '{print "20"$3"_"$1"_"$2}'`; \
mv $file $path; # "rename" the file \
done; \
popd; # restore original directory \
done;
This can be executed in folder above DATA. If you want to execute it directly in DATA, update the first loop to read for dir in *; do instead of DATA/*. It tells awk to use the - as the delimiter (instead of whitespace), and then reconstructs a string from "mm-dd-yy" to "20yy_mm_dd".
Using pushd and popd will enable the script to change the current directory to each subdirectory inside DATA (pushd) and then, after moving all necessary files will change back to the original (popd). Doing this will save you a lot of parsing-effort trying to save directory paths / etc.
You could use string manipulations and arrays to do that with bash only.
Something like:
for f in * ; do
parts=(${f//-/ })
mv "$f" "20${parts[2]}_${parts[1]}_${parts[0]}"
done
Search this site for various options to recurse into directories e.g.:
Shell script to traverse directories
Use the date command to convert the file name:
$ date -j -f %m-%d-%y 01-08-12 +%Y_%m_%d
2012_01_08
Getting to the files is a little tricker. We'll just switch directories to avoid dealing with long file paths.
for d in DATA; do
pushd "$d"
for f in *; do
new_f=$(date -j -f %m-%d-%y $f +%Y_%m_%d)
mv "$f" "$new_f"
done
popd
done
This site gives a good snippet
for i in *.avi; do j=`echo $i | sed 's/(\d{2})-(\d{2})-(\d{2})/20\3_\1_\2/g'`; mv "$i" "$j"; done

how to detect when compiler emits an error

To compile a C++ project, I want to write a perl script to compile my program and see if the compilation went wrong or not. If the compiler gives any compilation error, I'll need to perform some other task.
The perl script will be something like this:
#l1 = `find . -name '*.c'`;
#l2 = `find . -name '*.cpp'`;
#l3 = `find . -name '*.cc'`;
my $err;
my $FLAGS = "-DNDEBUG"
push(#l , #l1, #l2, #l3);
chomp(#l);
foreach (#l) {
print "processing file $_ ...";
$err = `g++ $_ $FLAGS`;
if($err == something) {
#do the needful
}
}
so what should be something?
You should check $? instead, after g++....
perlvar
$?
The status returned by the last pipe close, backtick (`` ) command,
successful call to wait() or waitpid(), or from the system() operator.
The exit value of the subprocess is really ($?>> 8)
So you should check if g++ returned 0 (success) or non-zero.
if ($? >> 8) {
/* Error? */
}
IPC::System::Simple/IPC::Run3 make this easier